visibilitychange事件监听整个页面的可见性状态变化,仅在标签页切走(hidden)或切回(visible)时触发,不涉及元素视口、css属性或dom渲染。

visibilitychange 事件到底监听什么
它监听的是整个页面的可见性状态变化,不是某个元素是否在视口内,也不是 CSS visibility 或 display 的切换。触发时机只有两种:用户切走标签页(变成 hidden)或切回来(变成 visible)。
注意:手机端 WebView、PWA、桌面端 Electron 等环境也支持,但 Safari 在某些旧版本中对后台定时器限制更激进,visibilitychange 是你唯一能可靠感知“页面被挂起”的信号。
怎么绑定和读取当前可见状态
用 document.addEventListener('visibilitychange', ...) 监听,状态通过 document.hidden(布尔值)或 document.visibilityState(字符串)获取。
-
document.hidden === true表示页面不可见(等价于document.visibilityState === 'hidden') - 可能的
visibilityState值还有'visible'、'prerender'(已废弃)、'unloaded'(极少出现) - 首次加载时不会触发事件,得手动检查
document.hidden判断初始状态
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
console.log('页面被切走了');
clearInterval(myTimer); // 比如停掉轮询
} else {
console.log('页面回来了');
myTimer = setInterval(pollData, 5000);
}
});
// 初始状态也要处理
if (document.hidden) {
clearInterval(myTimer);
}
常见误用和坑
很多人以为它能检测滚动进入视口,或者想用它替代 Intersection Observer —— 完全不是一回事。它只管“整个文档是否被用户主动聚焦”,跟 DOM 渲染、CSS 层叠、iframe 内容都无关。
- 不要在
visibilitychange回调里直接操作大量 DOM 或触发重排,因为可能在后台线程执行,浏览器会降频甚至跳过渲染 - Chrome 88+ 对后台页面的
setTimeout/setInterval最低间隔强制为 1s,但visibilitychange本身仍能即时触发 - iFrame 中的页面有独立的
visibilityState,父页面监听不到子 iframe 的切换 - 某些 Android WebView 或微信内置浏览器,在锁屏后可能不触发
hidden,需结合pagehide事件兜底
配合 pagehide / pageshow 更稳妥
当用户关闭标签页、刷新、导航离开时,visibilitychange 不一定触发(比如直接关 tab),而 pagehide 一定会。需要持久化状态或清理资源时,这两个事件最好一起用。
-
pagehide的event.persisted为true表示页面进了 bfcache(后台缓存),此时visibilitychange不会再触发 -
pageshow在从 bfcache 恢复时触发,比visibilitychange更早,适合恢复定时器或 WebSocket 连接 - 别在
pagehide里发网络请求(大多数浏览器会取消),要用navigator.sendBeacon()
window.addEventListener('pagehide', (e) => {
if (!e.persisted) {
// 非缓存场景,彻底清理
stopMediaTracks();
}
});
window.addEventListener('pageshow', (e) => {
if (e.persisted) {
// 从缓存恢复,重新激活逻辑
resumePlayback();
}
});
实际业务中,真正要处理的不是“页面可见不可见”,而是“用户是否还在 actively 使用这个页面”。visibilitychange 是最轻量的信号,但它的边界很清晰——只反映标签页焦点,别的都得靠组合判断。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











