canvas实现烟花效果需分发射、升空、爆裂、消散四阶段,每朵烟花独立计时;升空用匀减速,爆炸生成80–120粒子并按平方反比衰减速度;主循环统一驱动,防raf堆积;移动端适配touchstart并防抖;导出gif须用offscreencanvas逐帧控制。

用 Canvas 实现基础烟花爆炸效果
HTML 本身不支持粒子动画,必须靠 Canvas + JavaScript 控制帧绘制。核心是模拟“发射→升空→爆裂→消散”四个阶段,每帧更新粒子位置、透明度和半径。
关键点在于避免用 requestAnimationFrame 配合全局时间戳做统一驱动,否则多朵烟花会同步闪烁;应为每朵烟花独立维护生命周期计时器(如 age 和 lifeSpan)。
- 升空阶段用匀减速运动(
y -= velocity; velocity *= 0.97;),比线性更自然 - 爆炸时生成 80–120 个粒子,初始速度随机方向,衰减用平方反比(
speed *= 0.96;比*= 0.99更快收敛) - 粒子颜色别全用
"hsl(0, 100%, 60%)",建议从爆炸中心取主色,再加 ±20° 色相偏移,视觉更丰富
避免 requestAnimationFrame 堆积导致卡顿
常见错误是每次点击都无条件调用 requestAnimationFrame(animate),但没清理上一帧回调,造成多层嵌套循环,CPU 占用飙升。
正确做法是全局只保留一个动画主循环,所有烟花对象注册进数组,由主循环统一更新和渲染:
let animationId;
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
fireworks.forEach((f, i) => {
f.update();
f.draw();
if (f.isDead()) fireworks.splice(i, 1);
});
animationId = requestAnimationFrame(animate);
}
// 启动一次即可
animationId = requestAnimationFrame(animate);
注意:不要在 fire() 函数里反复调用 requestAnimationFrame,那是性能杀手。
移动端触摸触发烟花的适配要点
PC 端监听 click,移动端必须同时处理 touchstart,且要阻止默认行为防止页面滚动干扰:
- 绑定事件时加
{ passive: false },否则preventDefault()无效 - 用
event.touches[0].clientX取坐标,别用event.clientX(在 touch 事件中可能为 0) - 单次触摸可能触发多次
touchstart(尤其快速连点),加 150ms 防抖,或直接禁用连续发射(isFiring = true; setTimeout(() => isFiring = false, 150);)
导出为 GIF 时粒子模糊、帧率失控
Canvas 动画转 GIF 不是简单录屏——浏览器每帧渲染耗时不均,直接截帧会导致节奏错乱、粒子拖影严重。
真正可控的做法是:用 OffscreenCanvas(Chrome 69+、Firefox 72+)离屏逐帧生成图像数据,再交由 gif.js 或 omggif 编码。关键参数:
-
delay设为 40(对应 25fps),别用 100(10fps 太卡) - 粒子 alpha 值必须显式设为
ctx.globalAlpha = particle.alpha;,离屏 Canvas 不继承父级 alpha - 每一帧前务必调用
ctx.clearRect(0, 0, width, height),否则残影累积
如果目标浏览器不支持 OffscreenCanvas,老老实实用 canvas.toDataURL("image/png") 截图后拼接,但帧率只能压到 10–12fps,且文件体积翻倍。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











