如何在移动端可靠检测React应用的页面focus/blur状态
iOS Safari 端可靠的页面焦点/浏览状态检测方案
问题根因
你之前用的window层blur/focus事件绑定方案在iOS Safari上失效是系统策略导致的:
- 上滑关闭应用、切系统后台时,iOS会立即挂起页面JS执行线程,不会等待
blur事件完成派发,自然无法触发回调 - 从后台切回Safari时,在用户产生首次触摸/点击交互前,iOS会拦截所有自动触发的焦点类事件,防止页面未经用户许可偷跑逻辑,因此仅靠
focus事件无法在无交互场景下触发状态更新 - 桌面端没有这类JS挂起和交互拦截策略,所以原有方案可以正常运行
可靠实现方案
不要单一依赖focus/blur事件,采用多事件组合+优先级校验的方案,覆盖所有移动端场景:
- 以Page Visibility API为核心判断依据,这是目前移动端兼容性最好、触发时机最稳定的页面可见状态标准,iOS 11+全量支持
- 保留
focus/blur事件做桌面端兼容补充 - 绑定
pageshow/pagehide事件,覆盖Safari标签切换、页面前进后退缓存场景 - 兼容老版本iOS Safari的
webkitvisibilitychange私有前缀事件 - 增加首次交互兜底逻辑:切回页面后如果状态未同步,在用户第一次触摸屏幕时自动校准状态
React 可直接复用的实现代码
封装为自定义Hook,组件内直接调用即可拿到当前页面是否处于活跃浏览状态:
import { useEffect, useState } from 'react'; function usePageActiveStatus() { const [isActive, setIsActive] = useState(true); useEffect(() => { const syncStatus = () => { // 优先用可见性API判断,兜底用hasFocus const hidden = document.hidden ?? document.webkitHidden; if (typeof hidden === 'boolean') { setIsActive(!hidden); return; } setIsActive(document.hasFocus()); }; // 绑定所有需要监听的事件 const listenEvents = [ 'visibilitychange', 'webkitvisibilitychange', 'focus', 'blur', 'pageshow', 'pagehide' ]; listenEvents.forEach(eventName => { window.addEventListener(eventName, syncStatus); }); // iOS无交互切回兜底:首次触摸时校准状态,触发一次后自动解绑 const calibrateOnFirstTouch = () => syncStatus(); window.addEventListener('touchstart', calibrateOnFirstTouch, { once: true }); // 组件挂载时先同步一次初始状态 syncStatus(); // 组件卸载时清理所有监听 return () => { listenEvents.forEach(eventName => { window.removeEventListener(eventName, syncStatus); }); window.removeEventListener('touchstart', calibrateOnFirstTouch); }; }, []); return isActive; } // 组件内使用示例 function App() { const isPageActive = usePageActiveStatus(); useEffect(() => { if (isPageActive) { console.log('用户正在浏览当前页面'); // 恢复视频播放、消息轮询等逻辑 } else { console.log('页面已切到后台/失焦'); // 暂停播放、停止轮询等逻辑 } }, [isPageActive]); return <div>页面内容</div>; }
落地注意事项
- 状态变化对应的回调逻辑不要写高耗时操作,iOS切后台时给页面预留的JS执行窗口极短,执行超时会被系统直接中断
- 上滑杀应用的场景下,
pagehide和visibilitychange事件会在JS线程挂起前优先触发,完全可以替代blur事件的检测能力 - 如果需要兼容iOS 11以下的极老版本,可以额外绑定
resize事件做兜底,老版本Safari切后台时会触发窗口尺寸变化,辅助校准状态
内容的提问来源于stack exchange,提问作者GLHF
相关产品推荐
相关产品推荐

