用 canvas 实现粒子飘落特效更高效:复用画布、精简数据结构、控制数量(200–500)、时间校准 delta、剔除视口外粒子、避免强制同步布局,并添加轻量真实感(正弦偏移、透明度渐变)。

用 requestAnimationFrame 实现粒子飘落特效,核心是让每一帧只做必要计算、复用 DOM 元素(或用 Canvas)、避免强制同步布局。关键不在“怎么画”,而在“怎么不拖慢浏览器”。
用 Canvas 代替 DOM 粒子
每颗粒子都用 div 创建?几十个还行,上百个就会频繁触发重排重绘,掉帧明显。Canvas 是更合适的选择——所有粒子共用一个画布,纯 JS 控制绘制,GPU 加速友好。
- 创建一个全屏
<canvas></canvas>,设好width和height(别靠 CSS 拉伸,会模糊) - 用
ctx.beginPath()+ctx.arc()或ctx.fillRect()绘制粒子,比img或div轻量得多 - 每次动画帧先
ctx.clearRect(0, 0, width, height)清空,再批量重绘,逻辑清晰且可控
粒子数据结构要精简
每个粒子对象里只存真正影响渲染的字段,比如 x、y、vy(垂直速度)、size、alpha。别塞 element 引用、id、createdAt 这类非必需字段。
- 用
Float32Array存储大量粒子坐标和速度,比普通数组内存更省、访问更快 - 粒子总数控制在 200–500 之间较稳妥;超过可加“视口剔除”:
y > canvas.height + 50就重置到顶部 - 随机初始位置、大小、下落速度时,用
Math.random()即可,无需复杂物理库
requestAnimationFrame 的正确写法
不是简单套个递归调用就完事。要处理暂停、节流、时间校准,否则在后台标签页或低性能设备上容易失控。
- 用
let lastTime = 0记录上一帧时间戳,传入raf回调的timestamp可算出真实帧间隔(delta = timestamp - lastTime),用于匀速下落:y += vy * delta * 0.016 - 避免在动画循环里做 DOM 查询、样式读取(如
offsetTop)、console.log—— 这些都会强制同步布局,卡顿立现 - 页面不可见时(
document.hidden === true),自动暂停raf循环,节省资源
加点真实感但不伤性能
飘落效果不等于匀速直线下落。横向微偏移、轻微旋转、透明度渐变,都能提升观感,只要计算轻量。
- 横向偏移用正弦函数:
x += Math.sin(y * 0.01) * 0.5,周期性但开销极小 - 旋转可用
ctx.save()+ctx.rotate(),但只对少数大粒子用;小粒子直接跳过,改用不同形状(圆 vs 小方块)区分 - 透明度随高度变化:
alpha = Math.max(0.2, 1 - y / canvas.height),靠近底部更实,顶部更虚
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











