JavaScript Canvas 实现字符雨动画效果详解

作者:流萤时间:2026-10-25 12:43:16浏览:533

本文详细解析了利用 JavaScript Canvas 实现字符雨下落效果的原理与代码。通过控制黑色半透明背景的重绘频率实现字符渐隐,并结合随机概率算法控制各列字符的刷新节奏,从而营造出参差不齐的下落视觉体验。文章提供了从 HTML 结构、CSS 样式到核心 JS 类实现的完整代码示例,帮助开发者快速掌握该特效的制作技巧。

本文提供了使用 JavaScript Canvas 实现字符雨动画效果的具体代码示例,供读者参考学习。

字符雨效果

字符雨效果

实现原理分析

  • 字符雨从上往下逐渐消失的原理:在canvas中绘制字符时,每次循环都会重绘一层带有透明度的黑色背景。该黑色背景的透明度设置为 0.08(经测试此数值较为合适,也可调整以观察不同效果)。由于字符从上往下依次出现,上方字符先绘制,下方字符后绘制。程序重复绘制半透明黑色背景,使得上方先出现的字符逐渐被覆盖变暗,而下方后出现的字符保持相对清晰,从而形成字符逐渐消失的视觉错觉。
  • 部分列出现字符的控制逻辑:若不进行控制,canvas的每一列都会同时出现字符,导致效果整齐划一而非参差不齐。因此,引入一个代表出现机率的变量进行控制。当字符落到canvas底部时,程序生成一个随机数与出现机率进行比较。若随机数大于该阈值,则允许该列从顶部重新生成字符;否则,该列在当前循环中不生成新字符,需等待下一次循环再次比较随机数。通过这种机制,实现了部分列有字符、部分列无字符的随机分布效果。

实例创建步骤

let charRain = new CharRain("canvas_id");

HTML 结构搭建

<canvas id="canvas"></canvas>

CSS 样式设置

body{
      margin: 0;
      padding: 0;
      overflow: hidden;
}
#canvas{
  background-color: #111;
}

JavaScript 核心源码

;(function(win){

    /**
     * 创造字符雨
     */
    class CharRain
    {
      /**
       * @description CharRain 类的构造函数
       * @constructs
       * @param {string} canvas_id - canvas 元素的 id
      */
      constructor(canvas_id){
        this.canvas = document.getElementById(canvas_id);
        this.context = this.canvas.getContext("2d");
        this.bg_alpha = 0.08;    // canvas背景的透明度,也是字符消失的速度;取值范围:0 - 1
        this.appearRate = 0.95;  // canvas中每一列字符下落到底部后再次出现字符的机率;取值范围:0 - 1
        this.dropSpeed = 30;     // 字符下落速度
        this.fontSize = 17;     // 字符大小;也确定了字符列的数目,列之间的间距
        this.colunm = 0;        // 画布中的字符列的数目
        this.isColorful = false; // 是否呈现彩色字符雨,默认为经典黑底绿字
        this.drops = [];        // 记录每一列的字符下落的 y 值
        this.timer = null;      // 定时器
        this.chars = "abcdefghijklmnopqrstuvwxyz0123456789";  // 可选字符
        this.init();
      }

      /**
       * @description 初始化类
       */
      init(){
        let _this = this;
        this.setAttr();
        win.addEventListener("resize", function (){ // 添加浏览器窗口变化监听,重新设置相关属性
          _this.setAttr();
        });
        this.timer = setInterval(function (){       // 添加定时器,下落
          _this.draw();
        }, _this.dropSpeed);
      }

      /**
       * @description 设置类的一些属性
      */
      setAttr(){
        this.canvas.width = win.innerWidth;
        this.canvas.height = win.innerHeight;                     // 重新设置 canvas 的宽度和高度
        this.colunm = Math.ceil(win.innerWidth / this.fontSize); // 重新设置列数
        for (let i=0; i<this.colunm; i++) {
          if(!this.drops[i]) {                                    // 已经存在下落字符的列不用设置
            this.drops[i] = win.innerHeight;                      // 字符瀑布流直接开始下落
          }
        }
      }

      /**
       * @description 随机一个颜色
       * @return {string} rgba 颜色值
      */
      randomColor(){
        let r = Math.floor(Math.random()*256);
        let g = Math.floor(Math.random()*256);
        let b = Math.floor(Math.random()*256);
        return "rgba("+r+","+g+","+b+", 1)";
      }

      /**
       * @description 在画布上画出下落的字符
      */
      draw(){
        this.context.fillStyle = "rgba(1,1,1," + this.bg_alpha + ")";    // 叠加画黑色背景,通过不透明度,形成字符逐渐消失的效果
        this.context.fillRect(0, 0, win.innerWidth, win.innerHeight);    // 画矩形以清除之前画的字符
        this.context.font = this.fontSize + "px Consolas";               // 设置字符的大小、样式
        if(this.isColorful) {
          this.context.fillStyle = this.randomColor();                   // 呈现彩色字符雨
        } else {
          this.context.fillStyle = "#00cc33";                             // 经典黑底绿字
        }

        for(let i=0; i<this.colunm; i++) {                               // 在每一列上画出字符
          let index = Math.floor(Math.random() * this.chars.length);    // 随机一个字符
          let x = i * this.fontSize;
          let y = this.drops[i] * this.fontSize;                        // 字符在 y 轴方向上的距离
          this.context.fillText(this.chars[index], x, y);               // 画字符
          if (y>=this.canvas.height && Math.random()>this.appearRate) { // 字符落到底部 && 有再次出现的机率
            this.drops[i] = 0;                                          // 0 代表每一列的字符位置回到顶部
          } else {
              this.drops[i]++;                                            // 字符逐渐下落,字符在 y 轴上的距离增加一
          }
        } 
      }
    }

    win.CharRain = CharRain;
  }(window));

以上内容为本文的全部代码与解析,希望对读者学习有所帮助。欢迎继续支持本站获取更多技术资源。

作者最新文章