如何在关闭浏览器标签/窗口时执行JS代码,排除页面刷新场景
区分浏览器关闭与刷新,仅在关闭时执行函数
beforeunload事件确实会在页面刷新、关闭标签页/窗口时同时触发,无法直接区分这两种行为,但可以通过以下方案实现需求:
方案一:定时器 + 页面加载事件(最可靠)
核心逻辑:在beforeunload中设置延迟执行的定时器,若为刷新操作,后续会触发load事件,此时清除定时器;若为关闭操作,load事件不会触发,定时器到期后执行目标代码。
修改后的代码示例:
let unloadTimer; // 页面加载时清除关闭逻辑的定时器(刷新场景触发) window.addEventListener("load", () => { if (unloadTimer) { clearTimeout(unloadTimer); unloadTimer = null; } }); window.addEventListener("beforeunload", (event) => { event.preventDefault(); // 延迟执行关闭逻辑,给刷新操作留足清除定时器的时间 unloadTimer = setTimeout(() => { // 移除当前标签页的sessionStorage记录 sessionStorage.removeItem(tabKey); // 更新活跃标签列表并通知其他标签页 const activeTabs = JSON.parse(localStorage.getItem(tabKey)) || []; const updatedTabs = activeTabs.filter((id) => id !== tabId); if (updatedTabs?.length === 0) { // 所有标签页已关闭,执行状态更新请求 const id = events.getIdentifier(); const URL = `${API_URL}chat/change-status?url=${FIREBASE_FUNCTIONS_URL}&id=${id}&status=${Visitor_status.inactive}&chat_status=${chat_status.no_action}`; fetch(URL, { keepalive: true, }); } }, 500); // 延迟时间可按需调整,建议控制在500ms以内 });
方案二:监听刷新操作标记(补充方案)
通过监听键盘刷新快捷键、浏览器刷新按钮的鼠标事件,设置刷新标记,在beforeunload中判断是否跳过关闭逻辑。该方式能覆盖大部分刷新场景,但无法拦截所有刷新途径(如浏览器菜单刷新)。
示例代码:
let isRefresh = false; // 监听键盘刷新快捷键(F5、Ctrl+R、Cmd+R) window.addEventListener("keydown", (e) => { if ((e.key === "F5") || (e.ctrlKey && e.key === "r") || (e.metaKey && e.key === "r")) { isRefresh = true; } }); // 监听浏览器刷新按钮的鼠标悬浮事件(需根据不同浏览器适配选择器) document.addEventListener("mouseover", (e) => { if (e.target.tagName === "BUTTON" && e.target.title.includes("刷新")) { isRefresh = true; } }); window.addEventListener("beforeunload", (event) => { event.preventDefault(); if (isRefresh) { isRefresh = false; // 重置标记,避免影响下次操作 return; } // 执行关闭标签页的逻辑 sessionStorage.removeItem(tabKey); const activeTabs = JSON.parse(localStorage.getItem(tabKey)) || []; const updatedTabs = activeTabs.filter((id) => id !== tabId); if (updatedTabs?.length === 0) { const id = events.getIdentifier(); const URL = `${API_URL}chat/change-status?url=${FIREBASE_FUNCTIONS_URL}&id=${id}&status=${Visitor_status.inactive}&chat_status=${chat_status.no_action}`; fetch(URL, { keepalive: true, }); } });
注意事项
- 定时器延迟时间不宜过长,避免用户关闭标签页时产生明显等待;也不宜过短,防止刷新时来不及清除定时器。
- 必须保留
fetch的keepalive: true配置,确保页面卸载时请求能成功发送至服务器,避免因页面销毁导致请求中断。 - 方案二中的浏览器刷新按钮检测需要适配不同浏览器,部分浏览器的按钮选择器存在差异,建议作为方案一的补充使用。
内容的提问来源于stack exchange,提问作者Osama Ameer
相关产品推荐
相关产品推荐

