如何停止JS中通过new Audio()动态创建的音频元素?
问题描述
开发Canvas游戏时,最初使用如下代码批量停止页面所有音频:
document.querySelectorAll("audio").forEach((el) => { if ( el.id === "song1" || el.id === "song2" || el.id === "song3" ) { el.volume = 0; el.pause(); } else { el.currentTime = 0; el.volume = 0; el.pause(); } });
该方法仅能停止HTML文件<head></head>标签内的预加载音频,对动态创建的音频无效。
当前编写的音效控制函数如下:
function soundGo(newAudio, boolean) { if (boolean === true) { let audio = new Audio(newAudio); audio.volume = 0.1; audio.play(); } else { let audio = new Audio(newAudio); audio.volume = 0; audio.pause(); } }
现存问题:document.querySelectorAll无法获取到通过new Audio()创建的音频实例,现有停止逻辑不生效,尝试过相关社区方案仍未解决,需要实现遍历所有new Audio()创建的音频元素并批量停止的效果。
解决方案
问题核心原因有两个:
- 通过
new Audio()创建的音频实例如果没有被手动插入到DOM树中,本身就不属于DOM节点,document.querySelectorAll根本无法选中 - 原有音效函数的停止逻辑完全错误:停止分支里重新
new Audio()创建的是全新的独立实例,和之前正在播放的音频实例没有任何关联,调用pause()自然不会影响正在播放的音频。
可按如下方式改造实现需求:
- 全局维护一个
Set结构专门存储所有动态创建的音频实例,不要在创建播放后丢失实例引用 - 改造音效播放函数,创建音频实例后先存入全局集合,再执行播放逻辑;同时监听音频的
ended事件,播放完成后自动从集合中清理实例,避免内存泄漏 - 批量停止音频时,除了遍历DOM中已有的音频标签,同时遍历全局存储的动态音频实例执行停止操作即可
完整实现代码如下:
// 全局存储所有动态创建的音频实例 const audioInstances = new Set(); // 改造后的音效控制函数 function soundGo(audioSrc, isPlay) { if (isPlay) { const audio = new Audio(audioSrc); audio.volume = 0.1; // 将新创建的实例存入全局集合 audioInstances.add(audio); // 音频播放结束后自动从集合移除,减少无效内存占用 audio.addEventListener('ended', () => { audioInstances.delete(audio); }); // 捕获播放异常避免控制台报错 audio.play().catch(err => console.warn('音频播放异常:', err)); } // 删除原有else分支里新建音频实例执行暂停的错误逻辑 } // 全局批量停止所有音频的方法 function stopAllAudio() { // 先处理DOM内预加载的静态音频 document.querySelectorAll("audio").forEach((el) => { if (["song1", "song2", "song3"].includes(el.id)) { el.volume = 0; el.pause(); } else { el.currentTime = 0; el.volume = 0; el.pause(); } }); // 再处理所有动态创建、未插入DOM的音频实例 audioInstances.forEach(audio => { audio.pause(); audio.volume = 0; // 短音效直接重置播放进度,长背景音乐可按需保留进度 const audioName = audio.src.split('/').pop().split('.')[0]; if (!["song1", "song2", "song3"].includes(audioName)) { audio.currentTime = 0; } // 停止后从集合中移除实例 audioInstances.delete(audio); }); }
注意:如果后续有将动态创建的音频插入DOM的需求,上述批量停止逻辑依然生效,不会出现音频漏停的问题。
内容的提问来源于stack exchange,提问作者AJ Santaeugenia
相关产品推荐
相关产品推荐

