匀速运动需用时间差归一化位置更新(x += speed deltat),加速运动应积分速度(vx += ax deltat,x += vx * deltat),视觉缓动则用easing函数映射进度。

Canvas 中实现匀速与加速运动,核心在于正确更新物体的位置:匀速靠线性变化(速度恒定),加速靠二次或指数变化(加速度参与运算)。关键不是“画得多快”,而是“每帧位置算得准”。
匀速运动:用固定速度乘以时间增量
匀速即单位时间内位移相等。Canvas 动画通常基于 requestAnimationFrame,帧率不绝对稳定,所以不能简单每帧加固定像素(如 x += 2),而应结合时间差做增量计算。
- 记录上一帧时间戳(
lastTime),当前帧用performance.now()获取新时间戳 - 计算时间差
deltaT = (currentTime - lastTime) / 1000(转为秒) - 位置更新:
x = x + speed * deltaT(speed 单位是 px/s)
这样即使帧率波动(如从 60fps 掉到 40fps),物体在真实时间维度下仍保持严格匀速。
加速运动:引入加速度,用物理公式积分位置
常见加速(如自由落体、启动过程)本质是速度随时间线性增加,位置随时间呈二次增长。最稳的方式是显式维护速度变量,并每帧更新速度和位置:
- 初始化:
let vx = 0, vy = 0; const ax = 100, ay = 200;(加速度单位 px/s²) - 每帧更新:
vx += ax * deltaT; vy += ay * deltaT; - 再更新位置:
x += vx * deltaT; y += vy * deltaT;
这相当于对加速度做一阶欧拉积分,对大多数 Canvas 动画精度足够。若需更高精度(如长周期模拟),可改用半隐式欧拉或 Verlet 积分,但日常动效无需过度复杂化。
用 easing 函数实现“视觉加速”(非物理加速度)
很多 UI 动画要的不是真实物理加速,而是“先慢后快”或“先快后慢”的观感。这时可绕过物理模型,直接用 easing 函数映射动画进度 t ∈ [0,1] 到插值比例:
- 例如缓入(ease-in):
t * t(抛物线加速) - 缓出(ease-out):
t * (2 - t)或1 - (1 - t)² - 结合起止位置:
x = x0 + (x1 - x0) * ease(t)
注意:easing 适用于已知总时长的动画;若需实时响应(如鼠标拖拽跟随),仍推荐物理积分方式,更自然可控。
避免常见陷阱:帧率依赖与坐标累积误差
两个高频问题会破坏运动一致性:
-
硬编码帧增量:写成
x += 3看似简单,但在 30fps 下比 60fps 慢一倍,跨设备表现不一致 -
整数截断叠加:Canvas 坐标支持小数,但若反复
Math.round(x)再赋值,微小余量丢失会导致“卡顿感”或偏移漂移 - 建议全程用浮点数运算,仅在
ctx.fillRect(x, y, w, h)渲染时让 Canvas 自行处理亚像素渲染(现代浏览器默认开启)
匀速靠时间归一化,加速靠速度积分,视觉节奏靠 easing 映射——三者目标不同,选型要看需求本质:是模拟真实运动,还是服务用户感知。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










