JS鼓机按钮首次点击无效,二次点击才响应的问题解决求助
鼓机首次点击无响应问题解决方案
问题描述
我正在用JavaScript开发一款鼓机,目前遇到的问题是所有按钮首次点击时无响应,必须点击第二次才能正常触发音频播放与显示更新。猜测可能是函数初始化阶段未正确绑定点击事件,请教如何修改现有代码解决该问题?
问题原因
- 同时使用了HTML内联
onClick属性和JS的addEventListener绑定点击事件,两种事件触发顺序导致首次点击时音频播放与显示更新不同步,且浏览器自动播放策略可能拦截未预加载的音频首次播放请求。 - 音频元素未设置预加载,首次点击时资源尚未就绪,导致播放失败。
修改方案
- 移除按钮上的内联
onClick属性,统一通过JS绑定事件,避免逻辑冲突 - 给所有
<audio>标签添加preload="auto",提前加载音频资源 - 合并音频播放与显示更新逻辑到同一处理函数,保证操作同步
- 复用处理函数优化键盘事件逻辑,减少代码冗余
修改后的完整代码
HTML
<div id="drum-machine"> <div class="result" id="display"> <p></p> </div> <button class="drum-pad" id="0" name="Heater 1"> <audio class="clip" id="Q" src="https://s3.amazonaws.com/freecodecamp/drums/Heater-1.mp3" preload="auto"> </audio> Q </button> <button class="drum-pad" id="1" name="Heater 2"> <audio class="clip" id="W" src="https://s3.amazonaws.com/freecodecamp/drums/Heater-2.mp3" preload="auto"> </audio> W </button> <button class="drum-pad" id="2" name="Heater 3"> <audio class="clip" id="E" src="https://s3.amazonaws.com/freecodecamp/drums/Heater-3.mp3" preload="auto"> </audio> E </button> <button class="drum-pad" id="3" name="Heater 4"> <audio class="clip" id="A" src="https://s3.amazonaws.com/freecodecamp/drums/Heater-4_1.mp3" preload="auto"> </audio> A </button> <button class="drum-pad" id="4" name="Heater 6"> <audio class="clip" id="S" src="https://s3.amazonaws.com/freecodecamp/drums/Heater-6.mp3" preload="auto"> </audio> S </button> <button class="drum-pad" id="5" name="Open HH"> <audio class="clip" id="D" src="https://s3.amazonaws.com/freecodecamp/drums/Dsc_Oh.mp3" preload="auto"> </audio> D </button> <button class="drum-pad" id="6" name="Kick n' Hat"> <audio class="clip" id="Z" src="https://s3.amazonaws.com/freecodecamp/drums/Kick_n_Hat.mp3" preload="auto"> </audio> Z </button> <button class="drum-pad" id="7" name="Kick"> <audio class="clip" id="X" src="https://s3.amazonaws.com/freecodecamp/drums/RP4_KICK_1.mp3" preload="auto"> </audio> X </button> <button class="drum-pad" id="8" name="Closed HH"> <audio class="clip" id="C" src="https://s3.amazonaws.com/freecodecamp/drums/Cev_H2.mp3" preload="auto"> </audio> C </button> </div>
CSS
body { display: flex; justify-content: center; } #drum-machine { margin: 0 auto; display: flex; flex-flow: row wrap; justify-content: center; } #display { width: 200px; height: 60px; border: solid black; }
JavaScript
// 通用处理函数:播放音频并更新显示 function handleDrumTrigger(audioElement, displayText) { // 重置音频播放位置,避免重复点击时无法重新播放 audioElement.currentTime = 0; audioElement.play(); document.getElementsByClassName('result')[0].innerHTML = displayText; } // 绑定按钮点击事件 const drumPads = document.getElementsByClassName('drum-pad'); for (let i = 0; i < drumPads.length; i++) { drumPads[i].addEventListener('click', function(e) { const audio = this.querySelector('.clip'); const displayText = this.name; handleDrumTrigger(audio, displayText); }); } // 键盘事件处理 const keyCodes = [ { code: 81, name: "Heater 1", audioId: "Q" }, { code: 87, name: "Heater 2", audioId: "W" }, { code: 69, name: "Heater 3", audioId: "E" }, { code: 65, name: "Heater 4", audioId: "A" }, { code: 83, name: "Heater 6", audioId: "S" }, { code: 68, name: "Open HH", audioId: "D" }, { code: 90, name: "Kick n' Hat", audioId: "Z" }, { code: 88, name: "Kick", audioId: "X" }, { code: 67, name: "Closed HH", audioId: "C" } ]; document.addEventListener('keydown', function(e) { const keyData = keyCodes.find(item => item.code === e.keyCode); if (keyData) { const audio = document.getElementById(keyData.audioId); handleDrumTrigger(audio, keyData.name); } });
额外说明
- 添加
audio.currentTime = 0是为了让重复点击时音频可以重新从头播放,避免音频还在播放时点击无反应 - 使用
let替代var在循环中绑定事件,避免闭包导致的索引问题 - 键盘事件改用
find方法查找对应按键数据,代码更简洁高效
内容的提问来源于stack exchange,提问作者MaKeSi
相关产品推荐
相关产品推荐

