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

JavaScript30鼓点项目点击事件报Cannot read 'innerText'错误如何解决

报错原因

你遇到的报错是JS经典的var变量作用域+异步回调闭包问题,具体原因如下:

index.js:66 Uncaught TypeError: Cannot read properties of undefined (reading 'innerText') at HTMLDivElement. (index.js:66)

  • 你的for循环用var声明变量i,var不存在块级作用域,整个循环共享同一个i变量
  • 点击事件是异步回调,只有当你点击元素时才会执行,此时for循环已经执行完毕,i的值最终等于所有.key元素的总数量(你有9个按键,所以i=9)
  • 执行document.getElementsByTagName("kbd")[i]时,kbd元素总共有9个,索引范围是0~8,取索引9自然返回undefined,读取undefined的innerText属性就抛出了错误
  • 额外逻辑缺陷:即使i的问题修复,直接从全局取kbd列表匹配索引的写法也不健壮,若页面其他地方存在kbd元素就会出现匹配错误
修复方案

有两种常用修复方式,推荐优先用第二种:

方案1:替换变量声明关键字

把for循环的var i改成let i,let具备块级作用域,每次循环都会生成独立的i绑定,回调函数能正确捕获当前循环的索引值:

// 仅修改for循环第一行即可
for (let i = 0; i < document.querySelectorAll(".key").length; ++i) {
  document.querySelectorAll(".key")[i].addEventListener("click", function() {
    var keyPress = document.getElementsByTagName("kbd")[i].innerText;
    playAudio(keyPress);
    buttonAnimation(keyPress);
  });
}

方案2:直接从当前点击元素取值(更推荐)

点击事件回调里的this指向当前被点击的.key元素,直接在当前元素下查找kbd即可,完全不需要依赖循环索引,稳定性更高:

for (var i = 0; i < document.querySelectorAll(".key").length; ++i) {
  document.querySelectorAll(".key")[i].addEventListener("click", function() {
    // 直接取当前点击元素内的kbd文本
    var keyPress = this.querySelector('kbd').innerText;
    playAudio(keyPress);
    buttonAnimation(keyPress);
  });
}

额外优化提示

你当前的playAudio函数里所有case都引用了clap.wav,会导致所有按键播放同一个音效,按需求替换成对应的音效文件即可。

内容的提问来源于stack exchange,提问作者Sudhanshu Shekhar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 07:24:04