流畅canvas帧动画的关键是清屏干净、计算精准、切换稳定:每帧执行clearrect全清屏→更新状态→重绘;用requestanimationframe驱动并按deltatime更新逻辑;交互复杂选canvas逐帧绘制,简单播放可用img.src切换。

用 Canvas 制作流畅的帧动画,核心不在“画得多快”,而在于“清得干净、算得准、换得稳”。关键不是堆帧率,而是三步同步:清屏 → 更新状态 → 重绘,缺一不可。
必须每帧开头完整清屏
Canvas 是位图,不自动擦除上一帧内容。漏掉 clearRect 或只清部分区域,就会拖影、重叠、错位。
- ✅ 正确写法:
ctx.clearRect(0, 0, canvas.width, canvas.height)—— 覆盖整个画布,且不重置 fillStyle、lineWidth 等上下文设置 - ❌ 错误做法:用
canvas.width = canvas.width“偷懒清屏”——会清空所有绘图状态,后续描边变细、颜色丢失 - ⚠️ 响应式注意:若 canvas 用 CSS 缩放,
canvas.width/height是逻辑像素,clearRect 必须用这个值,不是 clientWidth/clientHeight
用 requestAnimationFrame 驱动,别用 setInterval
requestAnimationFrame 与屏幕刷新率同步(通常 60Hz),能避免丢帧、卡顿和时间漂移;setInterval 完全脱离刷新节奏,移动端尤其容易失真。
- 启动动画只需一次:
requestAnimationFrame(animate),函数内部再递归调用自己 - 不要在回调里做耗时操作(如遍历上千粒子、解析大 JSON)——主线程阻塞会导致整帧跳过
- 暂停动画用
cancelAnimationFrame(id),别靠 flag 控制循环,否则仍占用帧调度
按时间差(deltaTime)更新逻辑,而非固定步长
不同设备性能差异大。固定 x += 5 在高端机上飞快、低端机上卡顿;用实际间隔计算位移,才能保证速度一致。
- 记录上一帧时间戳:
let lastTime = 0 - 在 animate 函数中计算差值:
const deltaTime = timestamp - lastTime; lastTime = timestamp - 按目标速度换算位移:例如“每秒移动 120px”,则
x += (120 / 1000) * deltaTime
逐帧动画的两种落地方式
根据需求选:要交互控制(倒放、跳帧、变速)→ 用 canvas 绘制帧序列;仅简单播放静态序列 → 切换 img.src 更轻量。
-
Canvas 绘制帧序列(推荐):预加载所有 Image 对象,用
ctx.drawImage(frame, 0, 0)绘制。支持裁剪、缩放、叠加、滤镜,适合游戏或复杂动效 - img.src 切换(轻量):统一尺寸命名帧图(如 frame_001.png),提前 new Image() 触发缓存。注意 Safari 移动端对快速切换有延迟,帧间隔建议 ≥ 60ms
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











