梦亦同趋
\n```\n\n同时你的页面上需要创建一个canvas标签用来渲染内容:\n\n```js\n\n \n \n \n\n```\n\n`index.min.js`代码文件内部会通过id属性来获取`canvas`标签并渲染,所以canvas标签的id值需要和代码文件中选择器的id值一致(代码中的选择器的id是`container`)。如果你的canvas使用了其他id那么在代码文件中也要同步修改:\n\n```js\nfunction s() {\n W = document.querySelector('#container') //改成canvas的实际id\n var t = window.devicePixelRatio\n ;(W.width = window.innerWidth * t),\n (W.height = window.innerHeight * t),\n (W.style.width = window.innerWidth + 'px'),\n (W.style.height = window.innerHeight + 'px'),\n (G = new g['default'](W.width, W.height, t, N, I, {\n trailRate: 1,\n trailScaleRange: [0.2, 0.45],\n collisionRadius: 0.45,\n dropletsCleaningRadiusMultiplier: 0.28\n })),\n (z = (0, $['default'])(Y.width, Y.height)),\n (L = z.getContext('2d')),\n (B = (0, $['default'])(U.width, U.height)),\n (X = B.getContext('2d')),\n p(O, j),\n (q = new m['default'](W, G.canvas, z, B, null, {\n brightness: 1.04,\n alphaMultiply: 6,\n alphaSubtract: 3\n })),\n o()\n}\n```\n\n代码修改到此告一段落。\n\n### 下载渲染所需资源\n\n光修改代码是没办法成功渲染的,因为雨滴的渲染用到了背景图等资源,你需要下载[img](https://github.com/codrops/RainEffect/tree/master/demo/img)文件夹下的所有文件放到自己的项目中,渲染过程中会自动加载这些文件。\n\n![image.png](https://zhongfw.online/api/static/images/b3ee483c7db7051c81ee9f70a0674df3.png)\n\n如果图片路径正确且正常加载你应该能在项目中看到渲染好的页面,就像下面这样:\n\n![image.png](https://zhongfw.online/api/static/images/3403a5e8939ed2d869f4ff170069e102.png)\n\n### 更改背景图片\n\n将你自己的背景图片放到img文件夹下,修改index.min.js中的文件路径来加载你自己的背景图:\n\n```js\n{ name: \"textureRainFg\", src: \"./weather/texture-rain-fg.png\" },//src修改成你自己的背景图路径\n{ name: \"textureRainBg\", src: \"./weather/texture-rain-bg.png\" },//src修改成你自己的背景图路径\n```\n\n## 组件化重构(node package)\n\n不难发现上述使用方法较为繁琐且已无法与如今前端的工程化应用很好的配合(例如webpack,vite),本次重构工作将会以工程化为目的在不修改核心源代码的基础上开展,预计实现的特性如下:\n\n* 提供typescript的支持,这项工作将会在整个重构的生命周期中开展。\n* 开放出一些常用的配置:例如背景图,视频背景,雨滴参数等\n* 及其他...\n\n### 安装\n\n```bash\nnpm i aling-raining\n```\n\n**下称重构后的库为[Arain](https://www.npmjs.com/package/aling-raining)**\n\n### 基本使用\n\nArain的默认导出为Rain,你可以通过该类来初始化一个Rain实例,该类的基本结构如下:\n\n```typescript\nexport interface RainOptions { \n bg: string //背景图\n onInit?: () => void //当页面初始化完成时,此时已完成渲染\n fg?: string // 雨滴中反射的图像,一般是压缩后的背景图,不传默认使用背景图\n dropColor: string\n dropAlpha: string\n onAbort?: () => void //当动画终止时\n minR?: number // 最小水滴半径\n maxR?: number // 最大水滴半径\n maxDrops?: number // 最大水滴数量\n}\nexport default class Rain {\n private _id: string //canvas元素id,例如#my-canvas\n private _options?: RainOptions // 暴露的配置项\n constructor(id: string, options?: RainOptions) {\n this._id = id\n this._options = options\n }\n init() {\n // 初始化操作\n }\n abort() {\n // 终止操作\n }\n}\n```\n\n一个基本的图片背景渲染如下:\n\n```typescript\nimport { Rain } from 'aling-raining'\n\n//实例化Rain\nconst rainInstance = new Rain('#aling-rain-cover',{\n bg: './weather/texture-rain-bg.png',\n fg: './weather/texture-rain-fg.png',\n dropColor: './drop-color.png',\n dropAlpha: './drop-alpha.png',\n onInit() {\n onLoad?.()\n }\n })\n\n//初始化渲染\nrainInstance.init()\n```\n\n`./drop-color.png`和`./drop-color.png`是渲染的必须资源,你可前往[此处](https://github.com/codrops/RainEffect/tree/master/demo/img)下载。\n\n代码中的`#aling-rain-cover`是你页面中的canvas元素的id,动画最终会渲染到你的canvas中,所以你的代码中还需要有对应的`canvas`标签,就像下面这样:\n\n```html\n\n```\n\n:::error\n\n我们推荐`options.bg`为本地资源,例如`./public/yourbackgroundimg.png`,否则你可能收到以下报错:\n\n**`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.`**\n\n这是因为你的背景图属于跨域资源,当使用跨域资源(如图片)绘制内容,且该资源未正确设置 CORS 响应头(Access-Control-Allow-Origin),画布会被标记为“污染“。WebGL 的安全限制禁止污染的画布用于 texImage2D 等操作。\n\n:::\n\n### 视频背景\n\n从`v0.1.0`版本开始支持使用视频作为背景,与图片背景不同的是在初始化实例时你不再需要设置`bg/fg`属性,通过传递`video`属性来指定要渲染的视频元素:\n\n```typescript\nnew Rain('#aling-rain-cover', {\n video: '#video-el',\n onAbort() {\n console.log('abort')\n },\n minR: 30,\n maxR: 60,\n dropAlpha: 'img/drop-alpha.png',\n dropColor: 'img/drop-color.png',\n onInit() {\n console.log('init')\n }\n })\n```\n\n其中`video`是你的视频元素id,视频内容将被渲染到页面上。这意味着你需要自己管理视频元素,就像下面这样:\n\n```html\n\n\n\n\n```\n\n如果渲染成功最终将会实现如下效果:\n\n![video.gif](https://www.zhongfw.online/align-minio/memoryimage//2ca123ddd2f0352ba71c41e83ae16c80.gif)\n\n:::info\n\n我们推荐使用明亮的视频作为渲染源,因为雨滴的渲染是实时基于视频内容,如果视频不够明亮你可能会渲染出黑色的雨滴。`(*>﹏<*)′\n\n:::\n\n#### 实例方法\n\n##### init\n\n初始化实例,会重新加载图片资源(这是一个异步操作)并开始渲染,重复调用会启动多个渲染程序,无效渲染程序并不会自动关闭,这可能会导致你的页面卡顿,所以在启动前请终止上一次渲染。\n\n```typescript\nrainInstance.init()\n```\n\n##### abort\n\n终止一个渲染程序,会清除所有动画渲染及变量以释放内存,例如路由切换时调用。\n\n````typescript\nrainInstance.abort()\n````\n\n#### 实例化配置\n\n##### bg\n\n雨滴画布的背景图。\n\n##### minR\n\n雨滴的最小半径,默认10\n\n##### maxR\n\n雨滴的最大半径,默认40\n\n```typescript\nmaxR: 150\n```\n\n![image.png](https://zhongfw.online/api/static/images/76ada44b9ca78c91ebd812ad027cae81.png)\n\n##### maxDrops\n\n大雨滴的数量,默认900\n\n```typescript\nmaxDrops: 1\n```\n\n![image.png](https://zhongfw.online/api/static/images/6cd183e367ed758b9083227a7967c96d.png)\n\n此时页面上只有一个雨滴\n","mainEntityOfPage":{"@type":"WebPage","@id":"https://zhongfw.online/awsome/posts/c9b37a098263cea38606f03c82d4db4b"},"datePublished":"2025-06-25T02:03:37.569Z","author":{"@type":"Person","name":"Aling"}}

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

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

🎵

飞鸟和蝉-任然

this is my favourite song, hope you like it

如果你访问过本站首页,你或许会惊叹于本站落地页那真实的雨滴效果,该效果的实现来自于一个开源项目RainEffect(下称简称RE),该项目通过webgl实现了这些神奇的雨滴效果并让其他开发者得以使用。

不过由于该项目久远并缺少维护,哪怕是前端开发者现如今想要在项目中集成该效果并不容易,本文详细介绍了在项目中使用该项目的实践过程和基于该项目的重构方案,没有很复杂的逻辑,下面让我们开始。

#通过现有方案快速集成

如果你不想安装本人重构后的库并快速在项目中渲染可以选择此方式,这种方法通过直接引入js源码来在html中渲染雨滴,这也是重构完成前本站的使用方式。

#下载项目代码

将这个文件(RE)下载并放到你的目录中,我们后续将会通过script标签的方式引入该文件。

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

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

点击此处查看各个版本的渲染效果。

#修改下载的代码

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

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

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

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

index.min.js代码文件内部会通过id属性来获取canvas标签并渲染,所以canvas标签的id值需要和代码文件中选择器的id值一致(代码中的选择器的id是container)。如果你的canvas使用了其他id那么在代码文件中也要同步修改:

js
function s() { W = document.querySelector('#container') //改成canvas的实际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文件夹下的所有文件放到自己的项目中,渲染过程中会自动加载这些文件。

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修改成你自己的背景图路径

#组件化重构(node package)

不难发现上述使用方法较为繁琐且已无法与如今前端的工程化应用很好的配合(例如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()

./drop-color.png./drop-color.png是渲染的必须资源,你可前往此处下载。

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

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

#视频背景

v0.1.0版本开始支持使用视频作为背景,与图片背景不同的是在初始化实例时你不再需要设置bg/fg属性,通过传递video属性来指定要渲染的视频元素:

typescript
new Rain('#aling-rain-cover', { video: '#video-el', onAbort() { console.log('abort') }, minR: 30, maxR: 60, dropAlpha: 'img/drop-alpha.png', dropColor: 'img/drop-color.png', onInit() { console.log('init') } })

其中video是你的视频元素id,视频内容将被渲染到页面上。这意味着你需要自己管理视频元素,就像下面这样:

html
<canvas style="width: 100%; height: 100%;" id="aling-rain-cover"> </canvas> <video style="position: absolute; top: 0;" autoplay loop muted width="1" height="1" id="video-el" src="test.mp4"> </video>

如果渲染成功最终将会实现如下效果:

video.gif

#实例方法

#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

此时页面上只有一个雨滴