用requestAnimationFrame实现下雨特效需确保雨滴更新与屏幕刷新同步,核心是轻量数据结构、高效遍历、精准重置与精简Canvas渲染,并可选加入风偏移和景深增强真实感。

用 requestAnimationFrame 实现下雨特效,核心是让雨滴的更新与屏幕刷新同步,避免卡顿和掉帧。关键不在“画得多”,而在“算得准、动得顺”。
雨滴数据结构要轻量
每个雨滴只需保存最必要的属性:x(水平位置)、y(垂直位置)、speed(下落速度)、length(长度)、opacity(透明度),避免挂载 DOM 节点或冗余对象。用数组统一管理,不创建类实例也能高效遍历。
- 初始化时生成 100–300 个雨滴对象,随机分布于视口上方(y 为负值)
- x 在 0 到
window.innerWidth之间随机,y 在-100到-10之间 - speed 设为 5–15 像素/帧,length 控制在 10–30px,opacity 保持 0.6–0.9
动画循环必须用 requestAnimationFrame 驱动
不用 setInterval 或 setTimeout,直接用 requestAnimationFrame 递归调用主渲染函数。浏览器会自动对齐刷新率(通常是 60fps),且在标签页不可见时暂停调用,省资源。
- 每次帧回调中:更新所有雨滴的 y 值(
y += speed) - 若雨滴 y 超出视口底部(
y > window.innerHeight + 20),重置到顶部并随机 x 和 speed - 用
ctx.clearRect()清空画布,再用ctx.beginPath() → ctx.moveTo() → ctx.lineTo()绘制斜线雨滴
Canvas 渲染要精简,避免重绘开销
不要每帧新建 canvas 或调整大小。监听 resize 事件时仅更新 canvas 的 width 和 height 属性(不是 CSS 样式),并重设 ctx.scale 或 ctx.translate(如需适配高清屏)。
立即学习“前端免费学习笔记(深入)”;
- 启用硬件加速:给 canvas 添加
style="will-change: transform;" - 绘制前设好全局样式:
ctx.strokeStyle = '#fff'; ctx.lineWidth = 1; ctx.lineCap = 'round' - 避免阴影、渐变、文字等高开销操作;雨滴就是带角度的细线,用
ctx.stroke()一笔完成
可选增强:模拟风偏移与景深
提升真实感不需要增加太多计算量。给部分雨滴加轻微 x 方向偏移(windX),或按 y 值分层控制 opacity/speed,实现近大远小效果。
- 例如:雨滴越靠下(y 越大),
opacity *= 1.05,视觉上更“近” - 用
Math.sin(Date.now() * 0.001) * 2生成缓慢左右浮动的风偏移量,叠加到 x 上 - 把雨滴按 speed 分组:快的(远景)用细线+低 opacity,慢的(近景)略粗+稍高 opacity
不复杂但容易忽略的是:别在动画循环里做 DOM 查询、尺寸计算或 JSON 解析。所有静态值提前缓存,动态值只做加减乘。这样即使在低端设备上,也能稳稳跑满 60fps。



















