u-count-to 一闪而过是因参数错误或时机不当:start-val/end-val须为number、duration须为数字、decimals需匹配小数位;小程序需用uni.createselectorquery获取节点,禁用v-for重复实例,单位与千分位须后置处理,嵌套scroll-view会干扰requestanimationframe。

直接用 u-count-to 最稳,但参数配错、时机没卡准、单位混进组件里,三处一错,数字就“啪”一下闪完,根本看不出滚动。
为什么 u-count-to 一闪而过
不是组件坏了,是它默认只认三个数:起始值、目标值、持续时间——少一个或类型不对,动画就退化成赋值。
-
start-val和end-val必须是Number类型,写成字符串如"1200"会触发内部NaN,最终显示0或空白 -
duration必须显式传数字,比如1200,写成"1200"会导致计算异常,动画实际只有默认的 300ms - 要保留小数,
decimals得和end-val实际位数一致:比如end-val=899.65,就得设decimals="2" - 小程序中数据常在
onLoad后异步到达,此时节点还没挂载,autoplay="true"会失效;建议先设autoplay="false",等this.$nextTick()后再调this.$refs.uCountTo.start()
小程序里 countUp.js 报 target is null
这不是你代码写错了,是 uni-app 渲染时机和 DOM 节点可用性不一致。原版 countUp.js 直接 document.getElementById,但小程序没有真实 DOM。
- H5/APP 端可用
document.getElementById,但必须确保在onReady或$nextTick之后执行 - 小程序端必须走
uni.createSelectorQuery().in(this),且加.fields({ node: true })才能拿到可操作节点 - 拿到
res.node后不能直接传给原版countUp.js——它不认小程序虚拟节点;要么换countup-weapp,要么降级为手动requestAnimationFrame更新innerText - 别在
v-for每一项都 new 一个实例,复用同一实例 +update()更省资源
带单位(万/亿)和千分位的正确拼法
单位和分隔符绝不能塞进滚动逻辑里,否则缓动过程中它们会跟着跳、抖、闪。
- 单位(如 “万”)必须用计算属性拼接:
{{ (currentValue / 10000).toFixed(1) }} 万,而不是把"万"塞进u-count-to的end-val -
separator=","要开,它不只是美观——人眼识别1,245,678比1245678快 30% 以上;但旧版支付宝小程序不支持,得 fallback:String(num).replace(/\B(?=(\d{3})+(?!\d))/g, ",") - 别把
u-count-to塞进scroll-view:一旦父容器启用scroll-with-animation或频繁触发@scroll,就会抢占requestAnimationFrame调度权,导致卡顿、跳数
手写 requestAnimationFrame 滚动时的两个硬坑
自己实现看似自由,但结束判断错、四舍五入没处理好,数字就蹦高或抖动。
- 停止条件别用
current >= end,要用elapsed >= duration;帧率波动时某帧可能算出略超end的值,导致多执行一帧、“蹦高” - 缓动函数输出后必须四舍五入再赋值:
Math.round(current)或current.toFixed(1),否则小数累积会让视图抖动(尤其decimals="0"时) - 避免用
Math.round中间插值——比如从 100 滚到 103,中间算出 100.3→100.6→100.9→101.2,直接Math.round会变成 100→101→101→101→102,出现“卡住”感;改用Math.floor或保留一位小数显示 - 记得在组件卸载时清除动画帧:
cancelAnimationFrame(this.animationId),否则可能内存泄漏
最易被忽略的是:滚动动画不是独立模块,它和父容器渲染节奏强耦合。哪怕参数全对、时机也准,只要嵌套在 scroll-view 或开启了 scroll-with-animation 的容器里,requestAnimationFrame 就会被干扰——这不是 bug,是 uni-app 渲染链路里的确定性瓶颈。











