前言
在进行开发时遇到一个小问题,就是在用户关闭页签时如果某个状态是开启时那么就调用关闭接口。很简单的一个需求,它还能翻起什么浪花呢~
问题
onMounted(() => {
// 添加 beforeunload 事件监听器
window.addEventListener('beforeunload', handleCarBeforeUnload);
});
// 处理 beforeunload 事件
const handleCarBeforeUnload = (event) => {
// 只有开启状态退出时执行关闭
if (data.deviceStatus) {
API.closeDevice();
}
};
onBeforeUnmount(() => {
// 添加 beforeunload 事件监听器
window.removeEventListener('beforeunload', handleCarBeforeUnload);
});
简单,这样不就行了,然后->测试->失败。嘻嘻,md。
什么情况难道是没触发?,那就debugger
下看看, 结果是进入了, 那就奇怪了
那只能祭出无上AI大法了,于是得到了以下的结果
在 beforeunload
事件中使用 axios
调用接口可能会失败,原因主要有以下几点:
- 1. 页面卸载时异步请求不可靠
- 当页面开始卸载时,浏览器会逐步终止页面的 JavaScript 执行环境,包括未完成的异步请求(如
axios
的 HTTP 请求)。 axios
是基于XMLHttpRequest
或fetch
的异步请求库,而异步请求在页面卸载时可能被浏览器直接中断,导致请求无法完成。
- 当页面开始卸载时,浏览器会逐步终止页面的 JavaScript 执行环境,包括未完成的异步请求(如
-
2.
beforeunload
事件的限制beforeunload
事件的主要目的是提示用户是否确认离开页面,而不是用于执行复杂的逻辑(如发送请求)。- 浏览器可能会限制
beforeunload
事件中的代码执行时间,以确保页面能够快速卸载。
-
3. 解决方案:使用
navigator.sendBeacon
-
navigator.sendBeacon
是专门为页面卸载时发送数据设计的,它会在页面卸载时异步发送数据,且不会被浏览器中断。 -
将
axios
替换为navigator.sendBeacon
,可以确保请求成功发送。 -
示例代码:
-
window.addEventListener('beforeunload', handleCarBeforeUnload);
function handleCarBeforeUnload() {
const data = JSON.stringify({ event: 'page_unload', time: Date.now() });
navigator.sendBeacon('/your-endpoint', data);
}
那就试试呗, 修改->测试->失败。嘻嘻,md
解决
使用navigator.sendBeacon()
方法不行主要是此方法为post
请求,而我需要调用的是一个get
方法,那既然不能一步就尝试一下写个同步请求
const xhr = new XMLHttpRequest();
xhr.open('GET', '/your-api, false); // 同步请求
xhr.send();
嗯,不出意外->测试->失败。嘻嘻,md 我感觉主要是因为这个
浏览器可能会限制
beforeunload
事件中的代码执行时间,以确保页面能够快速卸载。
既然不行那真的是天要亡我吗,这点小问题就难住了,不行我得继续我的无上AI大法,于是就有了下面这个最终版的方法.
// 处理 beforeunload 事件
const handleCarBeforeUnload = (event) => {
// 只有开启状态退出时执行关闭
if (data.deviceStatus) {
const params = new URLSearchParams({
force: true,
_t: Date.now() // 防止缓存
});
// 方案1:使用 Image 对象(最可靠)
const img = new Image();
img.src = `/your-api?${params}`;
}
};
嗯,它是怎么能想到的呢 -.-
结语
至此就告一段落了,不得不说新脑子就是转得快啊~