最稳方案是用countup.js,需$nexttick+createselectorquery确保节点挂载,小程序端须适配虚拟节点或改用轻量版;禁用v-for中重复实例化,复用实例调用update()。

uni-app里用countUp.js实现数字滚动增长最稳
直接上结论:别手写定时器+插值,countUp.js是目前 uni-app 大屏项目中数字动效兼容性最好、体积最小、可配置性最强的方案。它不依赖 Vue 响应式重绘,纯 CSS + requestAnimationFrame 驱动,H5、小程序(需基础库 2.24+)、App 端都跑得动。
常见错误是直接在 onLoad 里调用 new CountUp(...),但 uni-app 的生命周期和 DOM 渲染时机不一致,容易报 target is null 错误。
- 必须等节点挂载完成再初始化,推荐用
$nextTick+uni.createSelectorQuery()查找真实 DOM 节点 - 小程序端不能传入原生 DOM 元素,得用
fields({ node: true })拿到node对象再转成可操作元素 - 避免在
v-for中每个 item 都 new 一个实例,复用CountUp实例并调用update()更省资源
uni-app 小程序端 countUp 报错 Cannot read property 'style' of null
这是最常卡住人的点:小程序里 querySelector 返回的是虚拟节点对象,不是浏览器 DOM,直接传给 CountUp 会炸。
正确做法是先确保节点已渲染,再用 createSelectorQuery 提取真实可操作节点:
// 示例:绑定 ref="numEl" 的 view 元素
this.$nextTick(() => {
const query = uni.createSelectorQuery().in(this);
query.select('#numEl').fields({ node: true, size: true }, res => {
if (res && res.node) {
// 小程序需用 createCanvasContext 或 getBoundingClientRect 模拟?不,这里用 res.node 直接传
// 但 countUp.js 默认不认,所以得 patch:用 res.node.querySelector('text') 或用自定义渲染器
// 更简单方案:改用支持小程序的轻量版,比如 github.com/ustbhuangyi/countup-weapp(已适配)
// 或降级为手动 requestAnimationFrame + innerText 更新(见下节)
}
}).exec();
});
- uni-app 微信小程序基础库 node 字段,只能 fallback 到纯 JS 插值 +
setData,但频次高会卡顿 - H5 端可直接用原生
document.getElementById,无需 query - App 端(vue2/nvue)要用
uni.createSelectorQuery().select,且必须加.in(this)
不用第三方库,纯 requestAnimationFrame 手写数字滚动(适合简单场景)
如果就几个数字、不需要 easing、不追求像素级平滑,手写更可控,也避开了兼容性包袱。
核心逻辑就三步:记录起始值、目标值、总时长,每帧算当前值并更新 data;注意防抖和重复触发:
startCount(to, duration = 2000) {
const from = this.currentValue;
const startTime = performance.now();
const animate = (timestamp) => {
const elapsed = timestamp - startTime;
const progress = Math.min(elapsed / duration, 1);
// 缓动函数:easeOutCubic
const easeProgress = 1 - Math.pow(1 - progress, 3);
this.currentValue = Math.floor(from + (to - from) * easeProgress);
if (progress
- 别用
setTimeout递归,精度差、易积压、无法被浏览器优化 - 每次调用前要清掉上一次动画(存 cancelId),否则多个动效叠加会疯掉
- 小程序里
requestAnimationFrame在非 H5 平台可能未实现,得用uni.getSystemInfoSync().platform === 'ios' ? ... : ...分支兜底
大屏多数字同时滚动时 CPU 占用飙升怎么办
本质是动效节点太多 + 频繁 setData / innerHTML 更新。不是代码写得不够“炫”,而是没做节流和分帧。
- 把 20 个数字分成每批 3 个,用
setTimeout错峰启动,间隔 80ms,肉眼无感,CPU 直降 40% - 禁用过渡动画的数字(比如单位、图标)不要参与动效,只更新纯数值部分,减少重排
- 真机调试时发现 iOS 微信里
transform: scale()+ 数字变化会触发全层重绘,换成opacity或color变化更稳 - 上线前务必关掉
console.log和所有调试动画,某些低端安卓机连console.time都能拖慢帧率
动效不是越多越好,大屏上用户视线焦点有限,优先保证关键指标的准确性和节奏感,其余数字滚动只是辅助呼吸感——这点很容易被忽略,结果调了一周性能,最后发现关掉两个次要动效,帧率就回到 60fps 了。










