结论:应自己封装Rate组件。因u-rate不支持拖动浮点值、App端有200ms延迟、半星交互不符淘宝体验;自研需处理touchstart/move/end,动态计算score并分三态渲染星星,且需区分短按与长按逻辑。

uni-app里用u-rate还是自己写?
直接说结论:官方u-rate(uView组件库)能跑,但默认样式和淘宝不一致,且在App端存在触摸反馈延迟、半星点击错位问题;真要还原淘宝那种「拖动打分+实时预览+点击即选」的体验,得自己封装一个轻量级Rate组件。
原因很简单:u-rate是为通用场景设计的,它的v-model绑定的是整数,不支持拖动过程中的浮点值;而淘宝评价里用户拖动星星时,中间那颗星会动态显示半星,松手才确定分数——这个交互必须自己控制value和hoverIndex两个状态。
- App端(iOS/Android)原生渲染下,
u-rate的@change事件有约200ms延迟,用户感觉“点了没反应” - H5端
u-rate支持拖动,但touchmove未节流,快速滑过时容易跳星 - 淘宝实际用的是「5颗星 + 1个浮动半星指示器」,不是简单切换class,而是计算触摸X位置与星星区域的相对比例
怎么实现拖动打分的Rate组件?
核心就三件事:监听touchstart/touchmove/touchend,算当前落在第几颗星、偏移多少,再把结果转成0.5步进的score(如2.5、3.0、4.5)。
关键细节:
- 每颗星用
view包裹,宽度固定(比如40rpx),用flex横向排列,禁用user-select: none -
touchstart时记录星星总数和单颗星宽度,存到data里,避免每次touchmove都重新查DOM -
touchmove里用event.touches[0].clientX - rect.left算相对X坐标,除以单星宽,得到小数值rawIndex(比如2.7),再Math.min(5, Math.max(0, rawIndex))防越界 - 展示时:前
Math.floor(score)颗星全亮,第Math.ceil(score)颗星按(score % 1) * 100%显示右半边或左半边(淘宝用右半边)
示例片段(template部分):
<view class="rate-wrapper" @touchstart="onTouchStart" @touchmove.stop.prevent="onTouchMove" @touchend="onTouchEnd">
<view v-for="(star, i) in 5" :key="i" class="star">
<image :src="getStarIcon(i)" class="star-icon" />
</view>
</view>为什么getStarIcon(i)不能只靠i < score判断?
因为淘宝的半星不是“第3颗星显示一半”,而是“第3颗星右边一半亮起”,所以图标得拆成两套:star-empty、star-half-right、star-full。如果只用整数比较,score=2.5时第3颗星该显示star-half-right,而不是star-empty或star-full。
常见错误写法:v-if="i < Math.floor(score)" → 这会让2.5分时第0~1颗星亮,第2颗星空着,完全不对。
- 正确逻辑:对每个
i(0~4),计算starValue = i + 1,然后比对starValue <= score(全亮)、starValue === Math.ceil(score) && score % 1 > 0(半亮)、其余(空) - App端注意:
image标签在nvue里不支持background-position,所以必须用三张图,不能靠CSS裁剪一张图 - H5端可优化:用
canvas动态绘制星星,减少图片请求数,但开发成本高,小项目不推荐
父子组件间怎么同步score且不破坏v-model习惯?
用户期望像用input一样写<Rate v-model="form.score" />,所以组件内部必须同时支持value prop 和 input事件(Vue 2)或update:value(Vue 3)。uni-app目前主流还是Vue 2,所以用value + @input最稳。
- 别用
v-model直接绑定data里的变量,否则touchmove频繁触发this.$emit('input', score)会导致父组件响应式更新卡顿 - 正确做法:
touchend才发input,touchmove只更新内部hoverScore用于UI预览 - 父组件监听
@change(自定义事件)接收最终值,比监听@input语义更清晰,也方便加防抖 - 兼容性注意:微信小程序基础库2.26.2+才支持
touch-action: none,老版本拖动时页面会跟着滚动,得在touchstart里event.preventDefault()
复杂点在于,淘宝的「长按拖动」和「短按点击」要区分处理——短按需立刻锁定分数,长按才进入拖动模式。这个阈值(通常300ms)得自己计时,不能依赖touchend自然触发。


















