我们需要增加监听浏览器的 刷新/关闭tab/页面切换/页面跳转 等事件,希望在触发这些事件的时候,可以立即向服务器发送统计数据。
beforeunload - 页面刷新/关闭
unload
pagehide
visibilitychange - 页面隐藏/可见
设置全局变量_pageHideListener,每次addEventListener之前,先移除已经存在的监听事件。
否则对同一事件和监听器监听多次,会造成最后remove的时候没有remove干净,监听器事件还是会发生。
采用 sendBeacon 异步发送数据,同时不会延迟页面的卸载或影响下一导航的载入性能。
export class WebAdapter{
private _pageHideListener?: (event: BeforeUnloadEvent) => void;
private _visibilityChangeListener?: () => void;
private _isSuccessCatchCloseEvent = false; // 判断是否已经触发了fun()函数的执行
public addPageHiddenListener(func: () => void) {
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
// 关键点:避免重复监听,如果已经被监听过了则需要先移除
this.removePageHiddenListener();
this._pageHideListener = (event) => {
// Cancel the event as stated by the standard.
event.preventDefault(); // 关键点
// Chrome requires returnValue to be set.
event.returnValue = '';
if (!this._isSuccessCatchCloseEvent) {
func();
this._isSuccessCatchCloseEvent = true;
}
};
this._visibilityChangeListener = () => {
if (document.visibilityState !== 'visible') {
func();
} else {
// 页面可见,需要重置_isSuccessCatchCloseEvent
this._isSuccessCatchCloseEvent = false;
}
};
window.addEventListener('beforeunload', this._pageHideListener);
window.addEventListener('unload', this._pageHideListener);
window.addEventListener('pagehide', this._pageHideListener);
document.addEventListener(
'visibilitychange',
this._visibilityChangeListener
);
}
}
public removePageHiddenListener() {
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
if (this._pageHideListener) {
window.removeEventListener('beforeunload', this._pageHideListener);
window.removeEventListener('unload', this._pageHideListener);
window.removeEventListener('pagehide', this._pageHideListener);
}
if (this._visibilityChangeListener) {
document.removeEventListener(
'visibilitychange',
this._visibilityChangeListener
);
}
}
}
}