☰
vue-devui Rate 评分组件完全指南:只读、动态、半选与自定义的源码级解析
2026/10/14 3:10:55 网站建设 项目流程
  • 前端
  • UI组件
  • 设计系统

【免费下载链接】vue-devui

基于全新 DevUI Design 设计体系的 Vue3 组件库,面向研发工具的开源前端解决方案。

项目地址:https://gitcode.com/DevCloudFE/vue-devui
点击查看免费下载

Rate 评分组件是 vue-devui(基于全新 DevUI Design 设计体系的 Vue3 组件库)中用于"等级评估"的交互组件,适用于用户对产品进行评分、对内容进行打星等场景。本文以组件官方文档(packages/devui-vue/docs/components/rate/index.md)为主体,结合组件源码(rate.tsx、rate-types.ts、rate.scss)与测试用例(rate.spec.ts),系统讲解 Rate 组件的只读模式、动态模式、半选模式、自定义外观等全部用法,并深入剖析其基于"宽度填充"实现星形部分高亮的底层原理,帮助你既会用、又懂其实现机制。

组件概览与使用场景

Rate 评分组件用于等级评估,最常见的应用场景是:

用户对一个产品进行评分时可以使用。

它支持只读展示(例如展示商品已获得的平均分)、可交互评分(用户点击/悬停选星)、半星粒度(支持 0.5 分)、自定义字符/图标/颜色以及成功/警告/错误三种语义色等多种能力,是"数据展示"类目下(见 组件注册入口 中category: '数据展示')功能完整(status: '100%')的组件之一。

安装与注册方式

Rate 组件在 index.ts 中对外导出,既支持全局注册也支持按需引入:

import type { App } from 'vue'; import Rate from './src/rate'; export * from './src/rate-types'; export { Rate }; export default { title: 'Rate 评分', category: '数据展示', status: '100%', install(app: App): void { app.component(Rate.name, Rate); }, };
  • 组件内部名称为DRate(见 rate.tsx 中name: 'DRate'),因此模板中统一使用<d-rate>标签;
  • 按需引入时直接import { Rate } from 'vue-devui'并在局部components中注册即可;
  • 类型定义RateProps等由export * from './src/rate-types'一并导出,方便 TypeScript 用户做类型提示。

基础用法:只读与动态两种模式

只读模式

当只需要展示评分结果、不允许用户交互时,设置:read="true"即可。此时鼠标悬停无预览效果、点击无法改变分值,光标显示为not-allowed(样式定义见 rate.scss 中.#{$devui-prefix}-rate--only-read规则)。

<template> <d-rate :read="true" v-model="valueReadonly" /> </template> <script> import { ref, defineComponent } from 'vue'; export default defineComponent({ setup() { const valueReadonly = ref(3.5); return { valueReadonly, }; }, }); </script>

注意:只读模式下v-model可以传入小数(如3.5),组件会根据小数部分自动渲染"整星 + 半星"的填充效果(详见下文"半选模式"与"源码实现原理")。

动态模式

默认情况下(read为false)组件处于动态交互模式,用户悬停可预览、点击即可提交评分:

<template> <d-rate v-model="valueDynamic" icon="star-o" /> </template> <script> import { ref, defineComponent } from 'vue'; export default defineComponent({ setup() { const valueDynamic = ref(2); return { valueDynamic, }; }, }); </script>

此处通过icon="star-o"指定了使用 devUI 图标库中的star-o图标作为评分图标。根据 rate.tsx 的渲染逻辑,icon参数最终会传给<d-icon>组件渲染(内部支持字体图标与 SVG 图标两种形态,见 use-icon-dom.tsx),因此只支持 devUI 图标库中存在的图标名。

自定义外观:字符、颜色与等级数量

动态模式-自定义

如果不想使用星星图标,可以通过character传入任意字符(如字母"A"),并通过color自定义激活色、通过count自定义总等级数:

<template> <d-rate character="A" color="#ffa500" v-model="valueCustom" :count="6" /> </template> <script> import { ref, defineComponent } from 'vue'; export default defineComponent({ setup() { const valueCustom = ref(3); return { valueCustom, }; }, }); </script>

上面的示例把评分图标替换为大写字母A,激活颜色设为橙色#ffa500,等级总数由默认的 5 级改为 6 级。需要注意:icon与character只能设置其中一个。从 rate.tsx 的渲染分支可以确认这一互斥关系:

  • icon && !character:渲染<d-icon name={icon}>;
  • character && !icon:渲染自定义字符文本;
  • !icon && !character:渲染组件内置的 SVG 五角星(默认形态)。

如果两者同时设置,character会被忽略。

使用 type 参数

type参数用于设置当前评分的语义类型,不同类型对应不同的激活颜色。RateStatusType支持'success' | 'warning' | 'error'三种取值:

<template> <div> <d-rate v-model="value1" :read="true" type="success" :count="5" icon="star" /> </div> <div> <d-rate v-model="value2" :read="true" type="warning" :count="5" icon="star" /> </div> <div> <d-rate v-model="value3" :read="true" type="error" :count="5" /> </div> </template> <script> import { ref, defineComponent } from 'vue'; export default defineComponent({ setup() { const value1 = ref(3.5); const value2 = ref(2); const value3 = ref(3); return { value1, value2, value3, }; }, }); </script>

三种 type 对应的激活星颜色在 rate.scss 中有明确定义:

type 取值激活星颜色(HEX)SCSS 类名
success#3dcca6(绿色)devui-rate__color--success
warning#fac20a(黄色)devui-rate__color--warning
error#f66f6a(红色)devui-rate__color--error

当不传type时,激活星默认使用主题品牌色$devui-brand(见.#{$devui-prefix}-rate__color-active规则)。另外值得留意的是,当同时设置了color参数时,颜色优先级高于type——从 rate.tsx 中默认图标分支可以看到:!color ? ns.em('color', type) : ns.em('color', 'customize'),即存在color时走自定义类,使用 CSS 变量--star-color着色。

半选模式与 change 事件

通过:allow-half="true"开启半选能力,用户点击星形左半侧即可得到 0.5 分的粒度;同时配合@change监听分值变化:

<template> <d-rate v-model="valueHalf" :allow-half="true" @change="change" /> </template> <script> import { ref, defineComponent } from 'vue'; export default defineComponent({ setup() { const valueHalf = ref(2.5); const change = (val) => { console.log(val); }; return { valueHalf, change, }; }, }); </script>

关于change事件的实现细节:在 rate-types.ts 中声明了onChange: (value: number) => void与onTouched: () => void两个 prop;在 rate.tsx 的selectValue中,点击后依次调用props.onChange(chooseValue.value + 1)、props.onTouched()并通过ctx.emit('update:modelValue', chooseValue.value + 1)同步 v-model。因此模板中的@change监听会收到改变后的分值作为回调参数。注意分值是 1 起始的(内部索引index从 0 开始,对外值为index + 1,半选时对应index - 0.5 + 1)。

另外在只读模式下也可以传入小数(如3.5)来展示半星效果,initRating会通过halfStar = chooseValue.value % 1计算小数部分并渲染对应宽度的半星。

API 参考

Rate 参数

参数名类型默认值描述跳转 Demo
readbooleanfalse可选,设置是否为只读模式,只读模式无法交互只读模式
countnumber5可选,设置总等级数只读模式
typeRateStatusType--可选,设置当前评分的类型,不同类型对应不同颜色使用 type 参数
colorstring--可选,星星颜色动态模式-自定义
iconstring--可选,评分图标的样式,只支持 devUI 图标库中所有图标动态模式
characterstring--可选,评分图标的样式,icon 与 character 只能设置其中一个动态模式-自定义
allow-halfbooleanfalse可选,动态模式下是否允许半选半选模式

从 rate-types.ts 的 props 定义可以补充以下细节:

  • modelValue(number,默认0):当前分值,即 v-model 绑定的值,支持小数以表达半星;
  • read(boolean,默认false)、count(number,默认5)、allowHalf(boolean,默认false)与文档表格一致;
  • type、color、icon、character默认均为空字符串,未设置时组件展示默认内置五角星 + 主题品牌色。

Rate 事件

事件名类型说明回调参数跳转 Demo
changeEventEmitter<number>分值改变时触发改变后的分值半选模式

组件声明了emits: ['change', 'update:modelValue'](见 rate.tsx),其中change由模板中的@change监听(Vue3 会将其注入为onChangeprop 并在选择时调用),update:modelValue用于支撑v-model双向绑定。

Rate 类型定义

RateStatusType
type RateStatusType = 'success' | 'warning' | 'error';

源码实现原理:宽度填充驱动星形高亮

理解了 API 之后,再来看看 Rate 组件在源码层面是如何把"分值"变成"半颗星"的。

数据结构:宽度数组

在 rate.tsx 中,组件维护了一个totalLevelArray数组,每个元素记录该颗星激活层的width(百分比字符串),例如100%表示满星、50%表示半星、0表示未点亮:

const totalLevelArray = ref<{ width: string }[]>([]); const chooseValue = ref(0); const initLevelArray = () => { totalLevelArray.value = []; for (let i = 0; i < props.count; i++) { totalLevelArray.value.push({ width: '0' }); } };

initRating则根据modelValue换算各星的宽度:整数部分对应的星设为100%,小数部分(halfStar > 0)所在的那颗星设为halfStar * 100 + '%',其余为0:

const initRating = () => { chooseValue.value = props.modelValue; const halfStar = chooseValue.value % 1; const intCurrentLevel = Math.floor(chooseValue.value); setChange(0, intCurrentLevel, '100%'); if (halfStar > 0) { totalLevelArray.value[intCurrentLevel]['width'] = halfStar * 100 + '%'; setChange(intCurrentLevel + 1, props.count, '0'); } else { setChange(intCurrentLevel, props.count, '0'); } };

组件在onMounted时执行初始化,并通过watch([() => props.modelValue, () => props.count])响应 v-model 与外部分值的变化。

双层图标 + overflow: hidden:部分填充的秘诀

每颗星在渲染时由两层图标叠放构成(见 rate.tsx 的render与 rate.scss 的样式):

  • 底层灰色图标:使用$devui-shape-icon-fill颜色(SCSS 变量,灰色),用于表达"未点亮"的完整星形;
  • 上层激活图标:带rate__active-star类,通过position: absolute; top: 0; left: 0; overflow: hidden;绝对定位叠在底层之上,其宽度由 JS 计算的百分比控制。当宽度为50%时,就恰好遮住左半颗星,视觉上形成"半星"。

激活层的着色由rate__color-active基类 +rate__color--success/warning/error/customize修饰类决定;其中customize模式使用 CSS 变量color: var(--star-color),而外层容器通过style={'--star-color: ' + color}注入自定义颜色,这也是color参数生效的通道。

交互三件套:mouseover / click / mouseleave

  • hoverToggle(e, index):非只读时,鼠标悬停把前index + 1颗星点亮,再根据鼠标在星内的偏移位置(isSemiSelected)决定当前星是50%还是100%,实现"悬停预览半星";
  • selectValue(e, index):非只读时点击提交,半选则chooseValue = index - 0.5,整选则chooseValue = index,随后回调onChange、onTouched并 emitupdate:modelValue(对外分值统一+1);
  • onMouseleave:鼠标离开时调用initRating()重置为 v-model 的实际分值。

其中半选判定是"按点击位置"计算的:

const isSemiSelected = (e: MouseEvent) => { const target = e.target as HTMLElement; return props.allowHalf && e.offsetX * 2 <= target.clientWidth; };

即allowHalf开启且点击落在星形左半侧时视为半选——这与官方文档中"动态模式下是否允许半选"的描述完全吻合。而在只读模式下,hoverToggle与selectValue都会因if (props.read) return;直接短路,彻底阻断交互。

命名规范

组件使用useNamespace('rate')生成 BEM 风格类名(见 use-namespace.ts),最终类名为devui-rate(块)、devui-rate__color(元素)、devui-rate--pointer/devui-rate--only-read(修饰符),SCSS 中通过$devui-prefix变量统一前缀,与组件库整体风格保持一致。

测试用例验证

rate.spec.ts 对上述行为提供了完整的自动化验证,是理解组件行为的最佳佐证:

  • 基础渲染:挂载d-rate后断言根容器devui-rate存在、devui-rate__color存在;设置color="red"后断言出现devui-rate__color--customize修饰类,验证了自定义颜色分支;
  • 动态交互:对第 4 颗星触发mouseover后,激活层style变为width: 100%(悬停预览);触发mouseleave后回到width: 0px(重置);依次点击第 1、3 颗星后,绑定的value从 0 变为 1、3,验证了点击评分与 v-model 同步;
  • 只读模式:在:read="true"下对第 1、3、4 颗星依次触发click,分值始终保持在初始的 3,验证了只读模式完全不可交互。

总结

vue-devui 的 Rate 评分组件以极简的 API 覆盖了评分场景的全部诉求:

  • 只读模式(read)用于结果展示,支持小数分值呈现半星;
  • 动态模式支持鼠标悬停预览与点击评分,配合allow-half可提供 0.5 分粒度;
  • 自定义能力覆盖图标(icon,devUI 图标库)、字符(character,与icon互斥)、颜色(color)与等级数量(count);
  • 语义色通过type(success/warning/error)一键切换;
  • 底层以"宽度百分比 + 双层星形叠加 + overflow hidden"实现任意比例的部分填充,交互与展示逻辑在 rate.tsx 中清晰可读,并配套了完整的测试保障。

掌握了这些参数与原理,你就可以在真实产品中根据业务需要灵活组合(例如"只读半星展示平均分 + 动态可评五星"),构建出符合 DevUI Design 规范且交互自然的评分体验。

  • 前端
  • UI组件
  • 设计系统

【免费下载链接】vue-devui

基于全新 DevUI Design 设计体系的 Vue3 组件库,面向研发工具的开源前端解决方案。

项目地址:https://gitcode.com/DevCloudFE/vue-devui
点击查看免费下载

相关推荐

上一篇:使用 .NET OpenTelemetry SDK 为 ASP.NET Core 配置分布式追踪、指标与日志:从 OTLP 导出到自定义 Span 与上下文传播
下一篇:uncloud 的 uc exec 命令详解:在运行中的服务容器内执行命令

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询