页面可见性检测依赖 document.visibilityState 和 visibilitychange 事件,需绑定在 document 上,支持值为 'visible'、'hidden' 等,但 iOS 存在误判,SSR 需判断环境。
document.visibilityState 和 visibilitychange 事件HTML5 提供了原生的页面可见性 API,不需要轮询或定时器。核心是两个东西:document.visibilityState(当前状态值)和监听 visibilitychange 事件。它比 blur/focus 更精准——比如用户切换到另一个标签页、最小化窗口、锁屏,甚至某些浏览器中打开开发者工具,都可能触发该事件。
visibilitychange 事件监听必须绑定在 document 上这个事件不会冒泡到 window,也不能用 addEventListener 绑在任意 DOM 元素上。只对 document 有效,且建议在脚本加载后尽早注册,避免漏掉初始状态变化。
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
console.log('页面变为可见');
} else if (document.visibilityState === 'hidden') {
console.log('页面被隐藏');
}
});
visibilityState 可能的值有:'visible'、'hidden'、'prerender'(已废弃,现代浏览器基本不返回)、'unloaded'(极少见)visibilitychange,但你可以直接读取 document.visibilityState 获取初始状态iOS Safari 对 visibilityState 的判断更保守。比如页面进入后台后,可能长时间维持 'visible';又或者播放视频/音频时,即使切到其他 App,visibilityState 仍为 'visible'(因媒体仍在运行)。这会导致你基于可见性做的逻辑失效。
pagehide 和 pageshow 事件作为补充visibilityState === 'hidden' 就暂停计时器或取消动画——iOS 下可能根本不触发Page Visibility API 相关的兼容性注意事项所有现代浏览器都支持,但 IE10+ 仅支持带前缀的版本:msvisibilitychange 和 msHidden。不过 IE 已淘汰,除非维护遗留系统,否则可忽略前缀。
'hidden' in document(返回 true 即表示支持)document.hidden 是旧式布尔属性,已被 visibilityState 取代,但仍可读(返回 true 等价于 visibilityState === 'hidden')document,相关代码需包裹在 if (typeof document !== 'undefined') 中,否则报错