title | date |
---|---|
浏览器关闭事件分析 |
2017/02/21 14:47:11 |
很多时候,我们可能会遇到这样一类需求:
- 浏览器关闭时,弹出一个新页面
- 浏览器关闭时,发送统计信息(如页面浏览时长)
- 浏览器关闭时,让用户二次确认
这个时候,我们就需要考虑如何判断浏览器关闭,如何阻止浏览器关闭,如何在浏览器关闭时,还是执行特定操作。
对于关闭与刷新判断,一般有以下几种做法:
首先基础都是通过监听 onbeforeunload
、onunload
等相关事件。
然后判断刷新与关闭:
- 判断鼠标坐标
- 判断键盘操作
- 判断事件间隔时长
其中,1和2一般是合起来使用。但也并不保险。关闭和刷新的快捷操作是可以自定义的。而且实现逻辑复杂。
在这里,我就重点来测试线通过判断事件间隔的方式来处理关闭与刷新的判断。
我们编写了如下测试代码
window.onbeforeunload = function () {
console.log('onbeforeunload', Date.now());
debugger
};
window.onunload = function(){
console.log('onunload', Date.now());
debugger
}
分别在浏览器上刷新和关闭,得到如下结果:
浏览器 | 关闭/刷新 | onbeforeunload | onunload |
---|---|---|---|
Chrome | 关闭 | [x] | [x] |
Chrome | 刷新 | [x] | [x] |
Firefox | 关闭 | [x] | [x] |
Firefox | 刷洗 | [x] | [x] |
Edge | 关闭 | [x] | [] |
Edge | 刷新 | [x] | [x] |
IE11 | 关闭 | [x] | [x] |
IE11 | 刷新 | [x] | [x] |
Edge关闭时,unload是否触发,还并不太确定(不太好验证)。
接下来,我们来验证两个时间的触发时间,测试代码如下:
window.onbeforeunload = function (evt) {
console.log('onbeforeunload', Date.now());
if (navigator.sendBeacon) {
navigator.sendBeacon('http://localhost:9999/?t=onbeforeunload', 'onbeforeunload');
}
window.start = Date.now();
};
window.onunload = function () {
console.log('onunload', Date.now());
if (navigator.sendBeacon) {
navigator.sendBeacon(`http://localhost:9999/?t=onunload&ts=${Date.now() - window.start}`, 'onunload');
}
window.open('http://10.16.85.170:8000/');
}
通过 navigator.sendBeacon
将间隔时间发送到后台进行查看。遗憾的是,IE和Edge并不支持该方法。
测试得出如下表格:
浏览器 | 关闭/刷新 | onbeforeunload | onunload | 时间间隔 |
---|---|---|---|---|
Chrome52 | 关闭 | [x] | [x] | < 5ms |
Chrome52 | 刷新 | [x] | [x] | > 20ms |
Firefox46 | 关闭 | [x] | [x] | > 200ms |
Firefox46 | 刷洗 | [x] | [x] | 10~100ms |
Edge13 | 关闭 | [x] | [] | N/A |
Edge13 | 刷新 | [x] | [x] | < 5ms |
IE11 | 关闭 | [x] | [x] | > 10ms |
IE11 | 刷新 | [x] | [x] | < 5ms |
根据这个表格,然后在按照自己的需要,就可以选择一个分割点来判断是刷新还是关闭。
当前未发现100%能判断清楚的方法,以上请酌情使用。
有一些场景,要求在浏览器关闭的时候,再次弹出一个确认框,那这个又应该如何实现呢?
关闭时询问,是一个比较标准化的处理了,只需要我们对 unbeforeunload
事件的 event
参数设置返回值,即可达到再次确认的效果。实现代码如下:
window.addEventListener('beforeunload', function(evt){
evt.returnValue = '您确定要离开了么?';
}, false);
注意:火狐为了避免不必要的弹窗,如果页面没有交互,是不会进行二次确认的,通过不会显示returnValue给用户。相关链接: https://developer.mozilla.org/zh-TW/docs/Web/API/WindowEventHandlers/onbeforeunload
很多时候,我们想在浏览器关闭/刷新时发送一些统计数据,之前的话,我们可以采用如下一些做法:
- 在
onbeforeunload
中使用同步Ajax - 发送Ajax,然后使用死循环,阻塞一个该事件。
这个功能作为一个比较大众化的需求,W3C中也有了一个针对性的草案,那就是浏览器对象的 sendBeacon
方法。
函数签名如下:
navigator.sendBeacon(url, data);
有了这个方法,我们就可以在合适的地方(诸如onbeforeunload)发送我们的统计数据,日志数据等等。
注意:该方法还是草案阶段,当前IE和EDGE暂不可用。