用 visibilitychange 监听页面可见性变化最稳定,document.hidden 为 true 时遍历所有 audio 元素并检查 readystate > 1 后调用 pause(),需兼容 pagehide/blur 并加 readiness 判断和环境兜底。

页面切到后台时 audio 不暂停?用 visibilitychange 监听最稳
浏览器标签页切走、最小化、锁屏时,<audio></audio> 默认不会自动暂停,用户可能在后台继续耗电/占音频通道。原生没这个自动行为,得自己监听页面可见性变化。
关键不是用 blur 或 focus(它们对 iframe、多 tab 切换不敏感),而是用 document.addEventListener('visibilitychange', ...) —— 这是 HTML5 标准方案,兼容 Chrome/Firefox/Safari/Edge(包括 iOS Safari)。
-
document.hidden为true表示页面不可见(切走、锁屏、新窗口弹出遮挡等) - 不要只监听一次:需在
visibilitychange触发时动态检查document.hidden,因为事件只通知“状态变了”,不带当前值 - 如果 audio 是动态创建的(比如播放列表切换),监听必须在 document 上全局注册,不能绑定在某个局部
<audio></audio>元素上
audio.pause() 失败?检查 networkState 和 readyState
调用 audio.pause() 报错或静默失败,常见原因是媒体还没加载完成,或网络中断导致状态异常。
先查两个关键属性:audio.networkState(是否连通)、audio.readyState(是否能播放)。只有 readyState >= 2(HAVE_CURRENT_DATA)才安全调用 pause();若 networkState === 0(NETWORK_EMPTY),说明资源根本没开始加载,此时 pause() 无意义。
立即学习“前端免费学习笔记(深入)”;
- 加个保护判断:
if (audio.readyState > 1) audio.pause(); - 避免在
loadstart之前就监听visibilitychange并立即 pause —— 此时audio可能还是空对象或未设置src - iOS Safari 对自动播放限制极严,即使调了
pause(),若之前没用户手势触发过播放,audio实例可能压根没解码能力,readyState会长期卡在 0
多个 audio 标签怎么统一控制?别用 class 选中,用 document.querySelectorAll('audio')
一个页面有背景音 + 播客 + 音效多个 <audio></audio>,想切后台时全停,别靠 getElementsByClassName 或手写 id 列表 —— 容易漏、难维护。
直接用 document.querySelectorAll('audio') 拿全部 audio 元素,再遍历调 pause()。注意:它返回的是 NodeList,不是数组,但支持 forEach(现代浏览器)。
- 示例:
document.addEventListener('visibilitychange', () => { if (document.hidden) { document.querySelectorAll('audio').forEach(a => { if (a.readyState > 1) a.pause(); }); } }); - 如果某些 audio 是循环背景音(比如游戏 BGM),想保留不暂停,加个自定义属性:
<audio data-no-pause="true"></audio>,查询时排除:document.querySelectorAll('audio:not([data-no-pause])') - 不要用
getElementsByTagName('audio')—— 返回实时HTMLCollection,遍历时若 DOM 变动可能出错;querySelectorAll是静态快照,更安全
安卓 WebView 或微信内嵌页失效?检查 visibilitychange 是否被禁用或延迟触发
部分安卓 WebView(尤其旧版 X5 内核)和微信内置浏览器,visibilitychange 事件可能不触发、延迟几百毫秒,甚至只在首次切后台时触发一次。
这不是代码写错了,是运行环境限制。可加一层保底:监听 pagehide(兼容性稍差但 WebView 支持更好),并用 setTimeout 延迟 300ms 再执行 pause(给事件兜底时间)。
- 组合监听:
document.addEventListener('visibilitychange', handler); document.addEventListener('pagehide', handler); - 避免重复暂停:用
audio._pausedByVisibility = true打标记,恢复时只 resume 被它暂停的实例 - 微信 iOS 端有个坑:锁屏后
visibilitychange不触发,但blur会——此时可降级监听window.addEventListener('blur', ...),仅限微信环境检测
visibilitychange 就以为万事大吉,真机一测才发现一半设备没反应。











