梦亦同趋
首页
记忆
链接
React组件化
webgl

【Rain Effect】效果的组件化实践

【Rain Effect】是一个令人惊叹的雨滴效果,您可本站首页看到其应用的效果。该js库较为古早且不支持配置,本文记录了将其重构及react组件化的实践过程。

Aling
2025-06-25
阅读时长
🎵

飞鸟和蝉-任然

this is my favourite song, hope you like it

你或许也惊叹于本站落地页那真实的雨滴效果,该效果的实现来自于一个开源项目RainEffect(下称简称RE)。

该项目通过webgl实现了这些神奇的雨滴效果并让其他开发者得以使用,不过由于该项目久远并缺少维护,现如今想要在项目中集成该效果并不容易,本文详细介绍下本站使用该项目的实践过程和基于该项目的重构方案。

#通过现有方案快速集成

如果你不想安装本人重构后的库并快速在项目中渲染雨滴可以选择此方式,这也是重构完成前本站的使用方式。

#下载项目代码

前往RE下载打包后的代码,将下载的代码文件放到你的项目中,我们后续将会通过script标签的方式引入该文件。

INFO

在上述下载代码的过程中,如果你回到了上级目录你会发现该文件下存在三个版本的index.js文件:图片背景(index.js,无背景(index2.js)和视频背景(index3.js)以及每个版本对应的未压缩版本,我们下载的是压缩版本index.min.js。点击此处查看各个版本效果。

#使用其他版本(未验证)

本人目前只使用了基础的版本也就是index.min.js图片背景,所以其他版本能否正常运行未知,如果你希望使用其他版本(例如视频背景)可以下载index3.min.js。

WARNING

不推荐使用未压缩版本,因为版本较老可能存在未解决的issue,目前确定的是该issue在图片背景的未压缩版本下确实存在。

#修改代码

在你的项目中通过script标签引入下载的文件,例如:

js
<script src="./index.min.js"></script>

同时你的页面上需要创建一个canvas标签用来渲染内容:

js
<body> <!-- 其他元素 --> <canvas id="container"></canvas> <script src="./index.min.js"></script> </body>

代码文件内部会通过id来获取canvas标签并渲染,所以id的值需要和代码文件一致,如果想使用其他id需要在代码文件中同步修改:

js
function s() { W = document.querySelector('#container') //改成其他id var t = window.devicePixelRatio ;(W.width = window.innerWidth * t), (W.height = window.innerHeight * t), (W.style.width = window.innerWidth + 'px'), (W.style.height = window.innerHeight + 'px'), (G = new g['default'](W.width, W.height, t, N, I, { trailRate: 1, trailScaleRange: [0.2, 0.45], collisionRadius: 0.45, dropletsCleaningRadiusMultiplier: 0.28 })), (z = (0, $['default'])(Y.width, Y.height)), (L = z.getContext('2d')), (B = (0, $['default'])(U.width, U.height)), (X = B.getContext('2d')), p(O, j), (q = new m['default'](W, G.canvas, z, B, null, { brightness: 1.04, alphaMultiply: 6, alphaSubtract: 3 })), o() }

代码修改到此告一段落。

#下载渲染所需资源

完成代码修改操作你的代码仍无法运行,因为雨滴的渲染用到了背景图等资源,下载img文件夹下的所有文件放到自己项目中的img文件夹中,渲染过程中会自动加载这些文件。

image.png

如果图片路径正确且正常加载你应该能在项目中看到渲染好的页面,就像下面这样:

image.png

#更改背景图片

将你的背景图片放到img文件夹下,修改index.min.js中的文件路径来加载你自己的背景图:

js
{ name: "textureRainFg", src: "./weather/texture-rain-fg.png" },//src修改成你自己的背景图路径 { name: "textureRainBg", src: "./weather/texture-rain-bg.png" },//src修改成你自己的背景图路径

#组件化重构

不难发现上述使用方法较为繁琐且已无法与如今前端的工程化应用很好的配合(例如webpack,vite),本次重构工作将会以工程化为目的在不修改核心源代码的基础上开展,预计实现的特性如下:

  • 提供typescript的支持,这项工作将会在整个重构的生命周期中开展。
  • 开放出一些常用的配置:例如背景图,雨滴参数等
  • 及其他...

#安装

bash
npm i aling-raining

下称重构后的库为Arain

#基本使用

Arain的默认导出为Rain,你可以通过该类来初始化一个Rain实例,该类的基本结构如下:

typescript
export interface RainOptions { bg: string //背景图 onInit?: () => void //当页面初始化完成时,此时已完成渲染 fg?: string // 雨滴中反射的图像,一般是压缩后的背景图,不传默认使用背景图 dropColor: string dropAlpha: string onAbort?: () => void //当动画终止时 minR?: number // 最小水滴半径 maxR?: number // 最大水滴半径 maxDrops?: number // 最大水滴数量 } export default class Rain { private _id: string //canvas元素id,例如#my-canvas private _options?: RainOptions // 暴露的配置项 constructor(id: string, options?: RainOptions) { this._id = id this._options = options } init() { // 初始化操作 } abort() { // 终止操作 } }

基本使用如下:

typescript
import { Rain } from 'aling-raining' //实例化Rain const rainInstance = new Rain('#aling-rain-cover',{ bg: './weather/texture-rain-bg.png', fg: './weather/texture-rain-fg.png', dropColor: './drop-color.png', dropAlpha: './drop-alpha.png', onInit() { onLoad?.() } }) //初始化渲染 rainInstance.init()

代码中的#aling-rain-cover是你页面中的canvas元素的id,动画最终会渲染到你的canvas中,所以你的代码中还需要有对应的canvas标签,就像下面这样:

html
<canvas id='aling-rain-cover'></canvas>
ERROR

我们推荐options.bg为本地资源,例如./public/yourbackgroundimg.png,否则你可能收到以下报错:

Failed to execute 'texImage2D' on 'WebGLRenderingContext': Tainted canvases may not be loaded. SecurityError: Failed to execute 'texImage2D' on 'WebGLRenderingContext': Tainted canvases may not be loaded.

这是因为你的背景图属于跨域资源,当使用跨域资源(如图片)绘制内容,且该资源未正确设置 CORS 响应头(Access-Control-Allow-Origin),画布会被标记为“污染“。WebGL 的安全限制禁止污染的画布用于 texImage2D 等操作。

#实例方法

#init

初始化实例,会重新加载图片资源(这是一个异步操作)并开始渲染,重复调用会启动多个渲染程序,无效渲染程序并不会自动关闭,这可能会导致你的页面卡顿,所以在启动前请终止上一次渲染。

typescript
rainInstance.init()
#abort

终止一个渲染程序,会清除所有动画渲染及变量以释放内存,例如路由切换时调用。

typescript
rainInstance.abort()

#实例化配置

#bg

雨滴画布的背景图。

#minR

雨滴的最小半径,默认10

#maxR

雨滴的最大半径,默认40

typescript
maxR: 150

image.png

#maxDrops

大雨滴的数量,默认900

typescript
maxDrops: 1

image.png

此时页面上只有一个雨滴

上次更新:2025-07-03 17:38:10
上一篇
前端常见算法
下一篇
关于2024年