Canvas粒子动画的核心在于结构清晰、更新高效、渲染可控:粒子类封装可配置行为,主循环解耦计算与绘制,通过数组清理、避免临时对象、距离阈值优化等细节保障60fps流畅运行。

Canvas粒子动画的核心不在炫技,而在结构清晰、更新高效、渲染可控。一个真正可用的粒子系统,不是靠堆粒子数量撑场面,而是靠合理的分层设计和关键细节处理来保障60fps流畅运行。
粒子类必须封装可配置行为
每个粒子不应是硬编码的“雪花”或“火星”,而应是一个能响应外部参数的独立个体。关键属性要支持动态注入:
- x、y:初始位置通常随机生成,但需适配画布尺寸(含devicePixelRatio缩放)
- size、speed、alpha:不设固定值,从配置对象读取,允许不同粒子类型有差异范围
- lifespan与age:用于控制存活时间,避免无限累积;重置逻辑(如雪落到底部后回到顶部)要写在update里,而非靠外部判断
- oscillationRange、windFactor等物理因子:让运动带自然感,而不是直线匀速下落
主循环必须解耦“计算”与“绘制”
requestAnimationFrame驱动的每一帧,应明确分为三个阶段:
- 清除:用ctx.clearRect(0,0,canvas.width,canvas.height),避免残留;高DPI设备需注意缩放后清空区域是否匹配
- 更新:遍历粒子数组调用每个粒子的update(),只改状态,不做任何绘图操作
- 渲染:统一调用draw(),批量提交绘制指令;圆形粒子优先用arc+fill,避免反复创建路径开销
性能瓶颈往往藏在“看不见”的地方
粒子数量上去之后,卡顿通常不是因为画得慢,而是因为以下几处没做约束:
- 数组增长失控:粒子死亡后必须从数组中移除,或用对象池复用,否则内存持续上涨
- 频繁创建临时对象:Math.sin、Math.random()调用本身不重,但若在update里new Color()或{ x, y },GC压力会明显上升
- 过度连线计算:粒子间连线(如鼠标跟随、粒子场连接)需设距离阈值(如120px),并用平方比较代替开方,跳过sqrt运算
- 未适配屏幕变化:resize时只重设canvas宽高,却忘了重置粒子位置范围,导致新粒子挤在左上角
扩展性来自配置驱动,而非硬编码分支
想支持雨、火、星、心形等多种效果,不需要为每种写一个新类。只需统一Particle基类,再通过配置对象切换行为:
- 雪花:启用sin扰动、小size、低alpha、底部重置
- 火焰:启用向上vy、随年龄变色(红→黄→透明)、生命周期短
- 鼠标跟随:目标点设为mouse坐标、加入缓动系数、限制最大粒子数防拖尾过长
- 烟花爆炸:单次发射后生成子粒子,子粒子带放射状初速度、衰减加速度、渐隐逻辑
不复杂但容易忽略



















