应使用v-for循环5次生成view,结合uni-icons的star-filled和star图标,根据评分值的小数部分动态渲染满星、半星或空星,并用touchstart配合getBoundingClientRect计算触摸位置实现精准半星交互。

uni-app里用v-for渲染5颗星最直接
不需要额外插件,纯Vue语法就能搞定。关键点是用v-for循环5次生成<view>,再根据当前评分值决定每颗星显示空心还是实心图标。推荐用uni-app自带的uni-icons组件(需先npm install @dcloudio/uni-ui),图标名分别是star-filled和star。
常见错误是直接用Math.round(score)取整——这会导致4.6分显示5颗星,但用户拖动时体验不连贯。更合理的是按小数部分做半星判断,比如4.3分就显示4颗实心+1颗半星(或4颗实心+1颗空心,取决于设计)。
- 评分值建议用
Number类型,避免字符串导致>=比较出错 - 每颗星绑定
@tap事件,传入索引i,计算新评分:score = i + 1(整星)或score = i + 0.5(半星) - 注意
touchstart比tap更适合拖动评分,但基础版先用tap够用
如何支持点击半星(如4.5分)
核心是监听touchstart并结合getBoundingClientRect()算点击位置。在<view class="stars">容器上绑定@touchstart="onTouchStart",然后在方法里获取触摸点相对于容器左边缘的clientX,除以单颗星宽度(比如80rpx),得到小数值。
示例逻辑:const ratio = (e.touches[0].clientX - rect.left) / rect.width;,再用Math.min(5, Math.max(0, Math.round(ratio * 10) / 2))得出带0.5精度的评分。这里rect.width必须是5颗星总宽,不能写死,否则不同屏幕适配会错乱。
- 别忘了在
onTouchStart里加e.preventDefault()防止页面滚动干扰 - 半星实现有两种:用两个重叠图标(实心+半透明空心),或直接用字体图标里的
star-half(需确认uni-icons是否包含) - 移动端触摸有延迟,建议加
catchtouchstart替代@touchstart避免冒泡冲突
props怎么设计才灵活
至少暴露三个参数:value(当前评分,v-model绑定)、disabled(只读模式)、size(单颗星大小,单位rpx)。如果支持半星,再加allowHalf布尔值。
容易被忽略的是value的校验逻辑:应该在watch里限制范围Math.min(5, Math.max(0, newVal)),否则外部传入6或-1会导致渲染异常。另外size默认设为40,但实际CSS里要用font-size: {{ size }}rpx控制图标大小,不能只改width/height——否则图标会拉伸变形。
-
value必须用Number类型声明,否则字符串"4.5"进来的===比较会失败 - 如果项目用
composition-api(如@vue/composition-api),props要写成defineProps({ value: Number }) - 禁用态下建议把
opacity设为0.4,并移除所有touch事件绑定,避免误触
真机调试时uni-icons图标不显示?
大概率是图标字体没正确加载。uni-app 3.0+ 默认用uni-icons,但H5端需要手动引入字体文件,App端和小程序端则依赖平台原生能力。检查node_modules/@dcloudio/uni-ui/lib/uni-icons/icons.css是否被引入(H5需在main.js里import '@dcloudio/uni-ui/lib/uni-icons/icons.css')。
另一个常见原因是图标名拼错:star-filled不是star_fill或filled-star,大小写和连字符必须完全一致。可以在uni-icons文档页搜索“star”确认可用图标列表。
- 小程序真机调试时,如果图标空白,打开开发者工具的“网络”面板,看
icons.ttf是否404 - App端遇到图标乱码,可能是自定义基座未打包图标字体,换官方基座重试
- 临时方案:不用
uni-icons,直接用Unicode字符★☆,但无法调色和缩放,仅限快速验证
半星交互的边界处理最易出错——比如用户手指从第1颗星滑到第5颗星,中间经过间隙区域时touchmove可能丢失坐标,导致评分跳变。实际项目中建议加防抖和坐标缓存,而不是只靠一次touchstart。


















