一般搜索结果都是一个监听事件, 即 onunload 或 onbeforeunload 事件, 但有一个致命性的缺陷, 那就是当用户刷新的时候这些事件同样也会触发. 这时候如何区分成为了难题.
这里给出一个区分的思路:
首先在浏览器内监听两个事件, 一个是载入事件 load, 另一个是销毁前的事件 onbeforeunload, 用户刷新后, 一定是先触发销毁事件然后是载入事件. 就是利用了这个顺序完成的监听过程.
触发销毁事件, 事件内部发送给后台一个请求,携带参数 eventName=load , 后台接收后先不要直接退出, 而是生成一个十秒左右的定时器, 定时器在十秒后自动注销当前账户. 用户刷新并触发载入事件时, 事件内部同样发送后台一个请求,携带参数 eventName=unload 后台接收后取消定时器.
如果是关闭浏览器, 则只触发上一步, 十秒后依然会自动退出. 这样就达到区分的目的了.
示例代码:
// 前端载入页面事件
window.onload = function () {
let httpRequest = new XMLHttpRequest() // 第一步:建立所需的对象
httpRequest.open('POST', '/user/logout') // 第二步:打开连接
httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
httpRequest.send('eventName=load') // 第三步:携带参数
httpRequest.onreadystatechange = function () {}
}
// 前端销毁页面事件
window.onbeforeunload = function () {
let httpRequest = new XMLHttpRequest() // 第一步:建立所需的对象
httpRequest.open('POST', '/user/logout') // 第二步:打开连接
httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
httpRequest.send('eventName=unload') // 第三步:携带参数
httpRequest.onreadystatechange = function () {}
}
// 后端 java 处理事件
// 使用 SaToken 进行演示
@PostMapping("/user/logout")
public void logout(String eventName) {
if (!StpUtil.isLogin()) {
System.out.println("未登录状态下什么都不做");
return;
}
System.out.println("执行退出: " + eventName);
if (eventName == null) {
System.out.println("用户正常点击按钮退出");
StpUtil.logout();
} else {
SaSession session = StpUtil.getSession();
String timerKey = "userCloseEventTimer";
if ("unload".equals(eventName)) {
System.out.println("10秒后退出");
Integer loginId = StpUtil.getLoginIdAsInt();
// 开启定时
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
System.out.println("自动退出");
StpUtil.logout(loginId);
}
};
Timer timer = new Timer();
timer.schedule(timerTask, 10_000); // 控制时长
session.set(timerKey, timer);
} else if ("load".equals(eventName)){
// 关闭定时
if (session.has(timerKey)) {
System.out.println("取消退出");
Timer timer = session.getModel(timerKey, Timer.class);
timer.cancel();
session.delete(timerKey);
}
}
}
}
十秒只是一个范围, 可以动态修改.
参考文献: load事件 beforeunload事件