You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在关闭浏览器标签/窗口时执行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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 08:02:52