audio不会自动暂停,需用visibilitychange监听document.hidden并遍历document.queryselectorall('audio')调用pause(),readystate>1才安全执行,react中应在useeffect清理函数返回同步stop,ios锁屏需pagehide兜底。

页面切到后台或用户离开时,audio 不会自动暂停——这是浏览器标准行为,不是 bug。必须手动监听可见性变化并调用 pause(),否则音频持续播放、耗电、占音频通道,iOS Safari 还可能直接中断后续播放。
用 visibilitychange 监听页面是否失焦
别用 blur 或 focus:它们对多标签切换、锁屏、弹窗遮挡不敏感,且在 iframe 里基本失效。visibilitychange 是 HTML5 原生方案,所有主流浏览器(含 iOS Safari)都支持。
- 监听必须注册在
document上,不能绑在某个audio元素或局部组件里 - 事件只通知“状态变了”,不带当前值;每次触发都要查
document.hidden - 判断逻辑要写成
if (document.hidden) { /* pause all audio */ },而不是只在首次触发时执行一次
多个 audio 标签怎么统一暂停?
别用 getElementsByClassName 或硬编码 ID 列表——漏一个就白干。直接用 document.querySelectorAll('audio') 拿全部实例,它返回 NodeList,现代浏览器可直接 forEach:
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
document.querySelectorAll('audio').forEach(a => {
if (a.readyState > 1) a.pause();
});
}
});
-
readyState > 1(即HAVE_CURRENT_DATA)是安全调用pause()的底线,避免静默失败 - 如果音频还没加载(
readyState === 0),pause()无意义,也不报错,但会让人误以为“没生效” - 移动端尤其要注意:iOS Safari 中,未被用户手势触发过播放的
audio,readyState可能卡在 0,此时跳过即可
React 里组件卸载时怎么停音频?
单页应用中,路由跳转 ≠ 页面刷新,visibilitychange 仍有效,但组件级清理更精准——尤其当你用 useSound 等库管理音频时。
- 不要在
useEffect里写window.addEventListener('beforeunload', ...):它只在关标签/关浏览器时触发,对 React 路由切换完全无效 - 清理函数必须返回一个同步执行的函数:
return () => sound.stop();,不是return sound.stop - 别误用
ref:若你用的是useSound,audioRef绑定到<div> 上再调 <code>pause()是无效的,得用库提供的stop或pause方法最容易被忽略的一点:visibilitychange 在 iOS Safari 锁屏后可能延迟触发,甚至不触发;如果你依赖音频暂停做关键状态同步(比如计时、权限释放),得额外加一层兜底——比如结合
pagehide事件,或者在音频播放前记录时间戳,切回前台时检查是否超时。











