// 是否是safari浏览器
const IS_SAFARI = typeof safari === 'object' && safari.pushNotification;
/**
* 监听dom状态
* @param { function } showCallback:页面在前景标签页中,并且窗口没有最小化时,的回调函数
* @param { function } hideCallback: 标签页处于后台时、窗口被最小化时、设备的屏幕被关闭时,的回调函数
*/
const ListenDocuemntState = function (showCallback, hideCallback){
let _showCallback = showCallback || function(){ };
let _hideCallback = hideCallback || function(){ };
const visibilitychangeHandel = () => {
/** 当:
* document的标签页处于后台
* 窗口被最小化
* 设备的屏幕被关闭。
*/
if(document.visibilityState === 'hidden'){
_hideCallback()
}
/**
* 当:页面内容至少是部分可见. 即此页面在前景标签页中,并且窗口没有最小化
*/
else if(document.visibilityState === 'visible'){
// 定时器的原因是想页面第一次渲染完毕后触发
setTimeout(() => _showCallback(), 0)
}
}
const pagehideHandel = () => _hideCallback();
document.addEventListener('visibilitychange', visibilitychangeHandel, false);
//Safari浏览器在页面hidden时存在兼容问题
if ( IS_SAFARI ) window.addEventListener('pagehide', pagehideHandel);
return {
reomve: function(){
document.removeEventListener('visibilitychange', visibilitychangeHandel);
if ( IS_SAFARI ) window.addEventListener('pagehide', pagehideHandel);
}
}
}
export default ListenDocuemntState;
使用方法:
import ListenDocuemntState from 'ListenDocuemntState'
const listen = ListenDocuemntState (()=>{
// 页面可见了 dosomething...
}, ()=>{
// 页面不可见了 dosomething...
})
// 移除
listen.remove()
另外推荐一个由谷歌团队维护的页面生命周期的方案:https://github.com/GoogleChromeLabs/page-lifecycle
它所提供的全面的生命周期:
- ACTIVE 激活
- PASSIVE 未激活(页面可以看到,但焦点不在此页面,打开开发者工具可以触发此状态)
- HIDDEN 隐藏,最小化、标签页切换都属于隐藏
- FROZEN 冻结
- TERMINATED 结束 (页面被关闭)
- DISCARDED 废弃(页面内容被浏览器清空)
其中,从 HIDDEN 状态到 FROZEN 状态之间的变化是有新的 API 事件名称检测的,分别是 resume 事件和 freeze 事件,使用示意如下:
document.addEventListener('freeze', (event) => {
// 页面被冻结
});
document.addEventListener('resume', (event) => {
// 页面解冻了
});
例如,我们希望页面离开时候上报数据,可以试试下面的代码,理论上应该是没问题的:
lifecycle.addEventListener('statechange', function(event) {
if (event.oldState == 'passive' && event.newState == 'hidden') {
navigator.sendBeacon('/log', postData);
}
});