JavaScript点击元素播放对应预设音频避免重叠的实现方法
问题根源
现有代码存在3个核心问题,直接导致音频重叠、代码冗余:
- 重复绑定事件:HTML标签内写了
onclick内联事件的同时,JS中又通过addEventListener绑定了同名回调,单次点击会触发两次播放逻辑。 - 事件监听器累积:每次点击触发播放函数时,都通过
addEventListener给音频对象新增ended事件回调,这些回调不会自动销毁,多次点击后会累积多个触发逻辑,同时拉起多个音频播放。 - 单动物单函数的写法扩展性极差,22个动物对应22个重复逻辑的函数,维护成本极高。
优化实现方案
采用配置化+统一逻辑的写法,后续新增动物卡片不需要重复写函数,同时从根源解决音频重叠问题:
- 首先简化HTML结构,去掉内联
onclick事件,通过自定义数据属性存当前卡片对应的音频索引、播放完成后要显示的下一张卡片ID:
<div class="container-fluid border"> <div class="cards-box row"> <!-- data-audio-index 对应当前卡片音频在音频数组中的下标,data-next-card 对应播完后要显示的下一张卡片ID --> <div class="cards border animate__animated animate__fadeIn" id="card1" data-audio-index="0" data-next-card="card2">Bear</div> <div class="cards border" id="card2" style="display:none;" data-audio-index="1" data-next-card="card3">Bee</div> <div class="cards border" id="card3" style="display:none;" data-audio-index="2" data-next-card="card4">Bird</div> <!-- 剩余19张卡片按相同格式补充即可 --> </div> </div>
注:原代码中动物名写为
Beer(啤酒)属于拼写错误,认知类儿童游戏注意修正为Bear(熊),避免误导儿童。
- 编写统一JS逻辑,不需要为每个动物单独写处理函数:
// 按卡片顺序存放所有动物音频,补全剩余19条音频路径即可 const voiceList = [ new Audio("./audio-files/Bears.mp3"), new Audio("./audio-files/bee.mp3"), new Audio("./audio-files/bird.mp3") ]; const clickSound = new Audio("./audio-files/click.wav"); clickSound.volume = 0.3; // 统一给所有卡片绑定点击事件 document.querySelectorAll(".cards").forEach(card => { card.addEventListener("click", () => { // 每次点击先重置所有音频状态:暂停播放、回到开头、清除之前的结束回调 [clickSound, ...voiceList].forEach(audio => { audio.pause(); audio.currentTime = 0; audio.onended = null; }); // 播放点击音效 clickSound.play(); // 点击音效播放完成后,播放当前卡片对应的动物音频 const targetAudioIndex = Number(card.dataset.audioIndex); const targetAnimalVoice = voiceList[targetAudioIndex]; targetAnimalVoice.volume = 0.5; clickSound.onended = () => { targetAnimalVoice.play(); // 动物音频播放完成后,显示下一张卡片 const nextCardId = card.dataset.nextCard; targetAnimalVoice.onended = () => { if (nextCardId) document.getElementById(nextCardId).style.display = "block"; } } }) })
方案说明
- 用
onended直接赋值的方式绑定音频结束回调,替代addEventListener,每次赋值会自动覆盖之前的回调,从根源解决监听器累积导致的多音频同时播放问题 - 每次点击先全局重置所有音频状态,确保同一时间只有一个音频在播放
- 逻辑完全统一,后续新增卡片只需要在HTML加对应DOM、在
voiceList数组中加对应音频路径即可,不需要新增任何处理函数,没有冗余代码
内容的提问来源于stack exchange,提问作者Sabmanny
相关产品推荐
相关产品推荐

