HTML怎么制作canvas烟花动画_HTML canvas烟花绽放动画实现【常见问题】

作者:袖梨 2026-07-27
Canvas烟花动画卡顿掉帧主因是未用requestAnimationFrame;须用其递归驱动、避免耗时计算、限制粒子数并复用粒子池;需每帧更新粒子位置与生命周期;用lighter混合模式替代阴影实现光晕;canvas宽高须设属性值而非仅CSS。

canvas 烟花动画卡顿、掉帧,是不是没用 requestAnimationFrame?

绝大多数卡顿问题根源就在这里——用 setTimeoutsetInterval 驱动动画,帧率不受控,还容易和浏览器刷新节奏错开。Canvas 动画必须用 requestAnimationFrame,它会自动对齐屏幕刷新率(通常是 60fps),且在标签页不可见时暂停执行,省资源。

实操建议:

立即学习“前端免费学习笔记(深入)”;

  • 永远把动画主循环写成递归调用:function animate() { /* 清空、更新、绘制 */ requestAnimationFrame(animate); }
  • 别在 animate 里做耗时计算(比如大量粒子坐标重算),可提前缓存物理参数或用固定步长简化运动模型
  • 如果烟花粒子数超过 300 个/帧,明显卡顿,就得考虑限制单次发射数量或启用粒子池复用(避免频繁 new 对象)

烟花爆炸后粒子“粘在空中不动”,是不是没更新 velocity 和 position?

这是初学者最常漏的一步:只画了初始爆炸效果,但没在每一帧中持续更新每个粒子的 vxvyxy。Canvas 是“一次性绘图”,不会自动记住上一帧状态。

实操建议:

立即学习“前端免费学习笔记(深入)”;

  • 每个粒子对象至少包含:{ x, y, vx, vy, radius, alpha, life }life 控制存活帧数或透明度衰减
  • 每帧必须执行:particle.x += particle.vx; particle.y += particle.vy; particle.vy += 0.05; // 模拟重力
  • 记得清理死亡粒子:particles = particles.filter(p => p.life > 0),否则数组无限膨胀拖慢 JS 执行

颜色发灰、没有“光晕感”,是不是没用 globalCompositeOperation 或阴影?

原生 Canvas 默认是“覆盖”模式(globalCompositeOperation = 'source-over'),多层亮色粒子叠在一起就变脏。真实烟花需要“叠加发光”效果,靠的是混合模式或模糊阴影。

实操建议:

立即学习“前端免费学习笔记(深入)”;

  • 绘制粒子前设:ctx.globalCompositeOperation = 'lighter'(Chrome/Firefox 支持,Safari 16+ 也支持),让亮色自动叠加增强亮度
  • 不用阴影也能模拟光晕:给粒子画两圈——先用大半径、低透明度画一次,再用小半径、高透明度画一次
  • 避免对每个粒子都调 ctx.shadowBlur,它开销大;统一用 lighter 混合 + 渐变色填充更高效

点击触发烟花没反应,event listener 绑在 canvas 上却点不中?

常见原因是 canvas 元素没设宽高(只靠 CSS 缩放),导致 getBoundingClientRect() 返回的坐标和 clientX/clientY 不匹配,计算出的点击位置偏移。

实操建议:

立即学习“前端免费学习笔记(深入)”;

  • canvas 的 widthheight 属性必须显式设置为整数(如 <canvas width="800" height="600">),不能只靠 CSS
  • 获取点击坐标时,用:const rect = canvas.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top;
  • 如果 canvas 被 transform 缩放,需额外除以 rect.width / canvas.width 校正比例

复杂点往往藏在坐标校准和生命周期管理里,而不是数学公式本身。粒子一多,filterforEach 的性能差异立刻显现,别等卡了才回头改结构。

相关文章

精彩推荐