You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

实现矩阵代码雨效果时store数组存储异常的技术求助

黑客帝国代码雨字符串更新异常问题

最近在CodePen学习JavaScript、HTML和CSS,实现《黑客帝国》风格的代码雨效果,具备其他编程语言基础。目前已实现包含随机字符串的div元素按周期向下滚动,但尝试将对应字符串以数组形式存入store数组,后续用于将字符串左移一位并添加新随机字符时,发现整个store数组的元素全部被设置为最新生成的字符串数组。

原代码

JavaScript代码

var numDivs = 10;
var pos = [];
var delay = [];

/* Check page is loaded and create each of the divs for the 'raindrops' */
for (let i = 0; i < numDivs; i++) {
  document.addEventListener('DOMContentLoaded', function() {
      var div = document.createElement('div');
      div.id = 'matrix'+i;
      div.className = 'matrixC m'+i;

      document.body.appendChild(div);
  }, false);
}

/* Generate 12 character string for each of the 'raindrops' */
var characters = ["日", "ハ","ミ","ヒ","ー","ウ","シ","ナ","モ","ニ","サ","ワ","ツ","オ","リ","ア","ホ","テ","マ","ケ","メ","エ","カ","キ","ム","ユ","ラ","セ","ネ","ス","タ","ヌ","ヘ","0","1","2","3","4","5","7","8","9","Z",":","・",".",'"',"=","*","+","-","<",">","¦","|","ç","ク"];

var store = [];
var state2 = "false";

function genNum() {
  var stringArr = [];
  for (let n = 0; n < numDivs; n++) {
    var finalString = "";
    var char = 0;
    if (state2 == "false"){
      var state = "false";
    }
    
    if (state == "false"){
      for (let m = 0; m < 20; m++) {
        let char = characters[Math.floor(Math.random() * characters.length)];
        finalString += char;
        stringArr[m] = char;
      }
      state = "true";
    }
    else {
      stringArr = store[n];
      stringArr.shift();
      let char = characters[Math.floor(Math.random() * characters.length)];
      stringArr[19] = char;
      for (let i = 0; i < stringArr.length; i++) {
        finalString += stringArr[i];
      }
    }
    store[n] = stringArr;
    console.log(n + ": " + finalString+", " + stringArr);
    console.log(store);
    document.getElementById("matrix"+n).innerHTML = finalString;   
  }
  state2 = "true";
}

setInterval(genNum, 100); /* Regenerate string from above every 0.15s */

let root = document.documentElement;
for (let i = 0; i < numDivs; i++) {
  pos[i]=((Math.random() * 100) + "vw"); /* Set random position across page */
}
for (let i = 0; i < numDivs; i++) {
  delay[i]=((Math.random() * 10) + "s"); /* Set random offset time for start of animation */
}


let dynamicStyles = null;

function addAnimation(body) { /* create animation function using parsed code */
  if (!dynamicStyles) {
    dynamicStyles = document.createElement('style');
    dynamicStyles.type = 'text/css';
    document.head.appendChild(dynamicStyles);
  }

  dynamicStyles.sheet.insertRule(body, dynamicStyles.length);
}

for (let i = 0; i < numDivs; i++) { /* For each 'raindrop' create animation from random point across page down to off-screen */
  addAnimation(`
  @keyframes fall`+i+` { 
    from {
      transform: translate(`+pos[i]+`,-150%);
    } 
    to {
      transform: translate(`+pos[i]+`,100vh);
    }
   }`);
}

/* Give each div their corresponding animation, specifying all details */
document.addEventListener("DOMContentLoaded", function () {
  for (let i = 0; i < numDivs; i++) {
    document.getElementById("matrix"+i).style.animation = "fall"+i+" 7.5s linear "+delay[i]+" infinite"; 
  }
});

CSS代码

body {
  background-color: black;
}

.matrixC {
  transform: translate(-200%,-200%); /* Make sure none are on screen at start*/
  font-size: 10px;
  width: 5px; /* Keeps text vertical */
  display: inline-block;
  text-align: center;
  word-wrap: break-word; /* Keeps text vertical */
  background: linear-gradient(black, #d0ebc4); /* Creates fade effect from bottom to top */
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  text-shadow: 0 0 20px #70ea37;  /* Creates glow */
  margin: -5px; /* For some reason makes it more evenly spread */
}

问题原因

核心问题是**stringArr数组在genNum函数的循环外定义,所有store[n]都指向同一个数组引用**。第一次循环时,所有雨滴复用同一个stringArr,修改它会同步影响store里的所有元素;后续state2=true后,虽然尝试取store[n],但初始时所有store元素都是同一个数组的引用,导致修改一个就全变。

另外,state变量的作用域错误:它在state2=false时才定义,且是函数内变量,无法针对每个雨滴单独控制状态。

修复方案

修改后的JavaScript核心代码(替换原genNum函数及相关变量)

var store = [];

function genNum() {
  for (let n = 0; n < numDivs; n++) {
    let finalString = "";
    // 把stringArr移到循环内,每个雨滴用独立数组
    let stringArr;

    // 检查store[n]是否存在,不存在则初始化
    if (!store[n]) {
      stringArr = [];
      for (let m = 0; m < 20; m++) {
        let char = characters[Math.floor(Math.random() * characters.length)];
        finalString += char;
        stringArr[m] = char;
      }
      store[n] = stringArr;
    } else {
      // 取当前雨滴自己的数组
      stringArr = store[n];
      stringArr.shift();
      let char = characters[Math.floor(Math.random() * characters.length)];
      stringArr.push(char); // 直接push更安全,避免索引越界
      // 拼接字符串
      finalString = stringArr.join('');
    }

    console.log(n + ": " + finalString+", " + stringArr);
    console.log(store);
    document.getElementById("matrix"+n).innerHTML = finalString;   
  }
}

关键修改点

  1. 将stringArr移到循环内部:每次循环都创建新数组,确保每个雨滴的字符串数组是独立的,不会共享引用。
  2. 用store[n]是否存在替代state/state2:逻辑更简洁,直接判断是否需要初始化当前雨滴的字符串数组。
  3. 用push替代直接赋值索引:避免数组长度变化时出现索引越界问题,shift()后数组长度减1,push()刚好补充到20位。
  4. 用join('')拼接字符串:替代手动循环拼接,代码更简洁高效。

额外优化:修复DOMContentLoaded绑定问题

原代码中循环绑定DOMContentLoaded事件会导致绑定多个相同事件,改为只绑定一次:

/* Check page is loaded and create each of the divs for the 'raindrops' */
document.addEventListener('DOMContentLoaded', function() {
  for (let i = 0; i < numDivs; i++) {
    var div = document.createElement('div');
    div.id = 'matrix'+i;
    div.className = 'matrixC m'+i;
    document.body.appendChild(div);
  }
}, false);

这样只会绑定一次事件,在页面加载完成后批量创建所有div,避免重复绑定的问题。

内容的提问来源于stack exchange,提问作者Josh Toole

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 01:19:52