uni-app 中 uni-rate 无法实现半星滑动,因其仅支持点击且内部以整数更新 v-model,CSS 截断模拟半星导致 change 事件无 0.5 值;H5 滑动跳星、小程序 touchmove 失灵、App nvue 伪元素失效;需自定义 touch 事件计算分值并限制边界。

uni-app 里为什么不能直接用 uni-rate 实现半星滑动?
因为官方 uni-rate 组件默认只支持点击,且半星逻辑是“视觉模拟”而非真实数据精度——它内部仍以整数为单位更新 v-model,再靠 CSS 截断实现“半颗”,导致 change 事件拿不到 0.5 这类中间值,也无法响应滑动。你在 H5 上拖着评分,手指一抬就跳回整星;小程序里 touchmove 偶尔失灵;App 端 nvue 下伪元素失效,半星直接不显示。
实操建议:
- 放弃依赖
uni-rate的半星能力,把它当纯展示组件用(只读场景) - 交互逻辑必须自己写:用
touchstart/touchmove/touchend+ 像素偏移换算分值 - 别信“设置
allow-half就能滑动”——那只是让点击支持半选,和滑动无关
怎么用原生 touch 事件算出半星值?关键在 handleTouchMove
核心不是“几颗星”,而是“当前触点落在第几颗星的哪个位置”。每颗星宽度设为固定值(比如 30px),用 clientX 偏移量除以它,再乘以步长(半星就是 0.5),最后四舍五入到最近的 0.5 倍数。
示例片段(Vue3 setup):
const handleTouchMove = (e) => {
const offsetX = e.touches[0].clientX - startX.value;
const rating = lastRating.value + offsetX / 30; // 30 是单星宽度
// 四舍五入到 0.5 的倍数:Math.round(rating * 2) / 2
modelValue.value = Math.max(0, Math.min(props.totalStars, Math.round(rating * 2) / 2));
};常见错误现象:
- 没做
Math.max/min边界限制 → 滑出范围后rating变负数或超总数 - 用
parseInt或Math.floor截断 → 半星永远进不了 - 在微信小程序里用了
event.target.dataset.index做滑动定位 → 小程序不支持动态 dataset 读取,得靠坐标计算
自定义图标时,background-image 在多端表现为啥不一致?
因为各端对 CSS 背景图的支持粒度不同:H5 完全支持;微信小程序禁止 base64 图片作 background;App 端 nvue 不支持 background-image,只能用 <image></image> 标签 + position: absolute 叠层;鸿蒙则要求图标必须是本地路径或 https,且尺寸严格匹配。
实操建议:
- 图标资源统一放
static目录,用相对路径引用,避免 base64 - 用
v-if区分渲染逻辑:v-if="$scope.platform === 'h5'"用 background,v-else-if="$scope.platform === 'mp-weixin'"用<image></image>+ class 控制显隐 - 别在 scoped style 里写伪元素 + background —— 小程序不支持
::before的 background-image
双向绑定失效?检查 v-model 和 update:modelValue 是否配对
Vue3 的 v-model 本质是语法糖:v-model="score" 等价于 :model-value="score" @update:model-value="val => score = val"。如果你封装成自定义组件但没触发 update:modelValue,父组件的 score 就永远不会变。
容易踩的坑:
- 在子组件里改了
props.modelValue—— Vue3 中 props 是只读的,直接赋值无效且控制台报错 - 用了
emit('change', val)但没同时 emit'update:modelValue'→ 父组件收不到同步信号 - 在
setup里用defineProps(['modelValue'])却忘了defineEmits(['update:modelValue'])
复杂点在于:滑动过程中要实时更新,但用户手指一抬才应提交最终值。所以得拆成两个状态——一个用于 UI 实时反馈(如 tempRating),一个用于 v-model 同步(只在 touchend 时 emit)。这个细节,90% 的开源组件都漏了。


















