必须用 document.visibilitystate 和 visibilitychange 事件监听页面可见性变化,它在切标签、最小化、锁屏时精准触发,比轮询或 hasfocus() 更准确省资源;需早期注册事件监听,通过 visibilitystate 获取当前状态,并注意其与 hidden 的区别及各类边界场景。

页面是否在前台可见,不能靠 document.hasFocus() 或定时轮询 window.innerWidth 判断——必须用 document.visibilityState 和 visibilitychange 事件。
怎么监听页面可见性变化
核心是监听 visibilitychange 事件,它只在页面可见性真正切换时触发(比如切标签、最小化窗口、锁屏),比轮询或焦点事件更准确、更省资源。
- 事件绑定只需一次,且应在页面加载早期注册(比如
DOMContentLoaded阶段) - 回调中通过
document.visibilityState获取当前状态:"visible"、"hidden"、"prerender"(已基本废弃)、"unloaded"(极少出现) - 不要在回调里直接调用耗时操作(如重绘 canvas 或发起请求),可加节流或延迟判断
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
console.log('页面回到前台');
} else if (document.visibilityState === 'hidden') {
console.log('页面被隐藏');
}
});
visibilityState 和 hidden 属性的区别
document.visibilityState 是字符串值,语义清晰;document.hidden 是布尔值,仅反映“是否隐藏”,二者逻辑一致但用途不同。
- 优先用
visibilityState:能区分"visible"和"prerender",便于做细粒度控制(比如 prerender 阶段不初始化媒体播放器) -
document.hidden仅用于快速布尔判断,兼容性略好(IE10+),但现代项目无需降级至此 - 注意:
document.hidden === true等价于document.visibilityState === 'hidden',但不等价于'prerender'
常见误判场景和应对方式
很多“不可见”不是由用户主动切换导致的,比如 iOS Safari 在后台播放音频时仍报告 visible,或 Android PWA 被系统休眠后事件不再触发。
- 不要假设
visibilitychange一定能捕获所有隐藏场景:锁屏、进程被杀、WebView 后台限制下可能完全不触发 - 对关键逻辑(如暂停视频、停止心跳请求)建议组合判断:
document.hidden+document.hasFocus()+ 页面是否在pagehide状态 - iOS Safari 中,若页面有
<audio></audio>自动播放且未静音,即使切到后台也可能维持visible状态——此时需监听pause事件辅助判断 - Web Worker 中无法访问
document,Visibility API 不可用,需由主线程同步状态过去
实际应用中的边界处理
Visibility API 不是万能开关,尤其在复杂单页应用中,它的触发时机和可靠性受浏览器实现影响较大。
- SPA 路由切换不会触发
visibilitychange,它只响应浏览器级可见性变化 - 测试时别只用 Chrome 切标签:Safari 的锁屏行为、Firefox 的多进程模型、WebView 的嵌入限制都可能导致差异
- 服务端渲染(SSR)页面首次加载时,
document.visibilityState可能为"prerender"或"visible",取决于预渲染策略,需在DOMContentLoaded后读取 - 如果依赖可见性启动长任务(如数据分析上报),记得加超时兜底:避免因事件丢失导致逻辑永久挂起
Visibility API 的价值不在“绝对精确”,而在于提供一个轻量、标准、跨浏览器的信号源——但它从不承诺 100% 覆盖所有隐藏路径。真正在意后台行为的逻辑,得自己补上容错层。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










