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

Vue.js项目中如何区分用户关闭标签、跳转页面还是刷新页面

你之前的判断逻辑失效的核心原因是:beforeunload触发时读取的performance.navigation.type/PerformanceNavigationTiming.type记录的是当前页面的加载来源,不是本次页面卸载的触发原因,所以三种场景下拿到的都是上一次导航的结果,自然无法区分。

以下是可落地的实现方案:

方案1:基于SessionStorage区分刷新/关闭,实现成本最低

SessionStorage的生命周期和当前标签页绑定,页面刷新时数据保留,关闭标签/浏览器后自动清空,刚好匹配你的需求:

created() {
  // 页面加载时判断是否为刷新场景
  const isRefresh = sessionStorage.getItem('game_session_active') === 'true'
  if (isRefresh) {
    // 刷新场景,直接恢复现有Firestore游戏数据即可
    this.restoreGameState()
  } else {
    // 首次进入/关闭后重新进入,清理残留的旧游戏数据
    this.clearObsoleteGameData()
  }
  // 标记当前会话激活
  sessionStorage.setItem('game_session_active', 'true')

  // 注册beforeunload监听
  window.addEventListener("beforeunload", (event) => {
    this.stopFirestoreListeners("beforeunload")
    // 不需要在这里删除Firestore文档:
    // 1. 刷新场景下SessionStorage标记保留,下次加载会识别为刷新,不会清理数据
    // 2. 关闭/跳转场景下SessionStorage自动清空,下次加载会触发旧数据清理
  });

  // 处理浏览器bfcache回退场景
  window.addEventListener('pageshow', (event) => {
    if (event.persisted) {
      this.startFirestoreListeners("pageshow")
    }
  })

  this.startFirestoreListeners("created");
}

方案2:配合Firestore原生能力,可靠性更高

前端beforeunload事件本身不可靠,浏览器可能直接终止页面进程,导致你写的删除逻辑没机会执行。针对你用Firestore的场景,直接用官方提供的onDisconnect断连触发机制更稳妥:

// 初始化游戏文档后设置断连操作
const gameDocRef = db.collection('games').doc(this.gameId)
// 配置断开连接1分钟后自动删除文档,给刷新预留足够的重连时间
await gameDocRef.onDisconnect().set({
  autoDeleteAfter: Date.now() + 60 * 1000
}, { merge: true })

// 页面加载完成后,验证游戏文档状态
const gameDoc = await gameDocRef.get()
if (gameDoc.exists && gameDoc.data().autoDeleteAfter > Date.now()) {
  // 刷新场景,取消之前的断连删除计划,保留文档
  await gameDocRef.onDisconnect().cancel()
  await gameDocRef.update({ autoDeleteAfter: FieldValue.delete() })
  this.restoreGameState(gameDoc.data())
} else {
  // 新会话场景,创建新的游戏文档
  this.createNewGame()
}

补充:区分跳转页面场景

如果需要单独识别用户点击链接/提交表单跳转的场景,可以提前加全局标记:

// 全局标记是否为主动跳转
let isActiveNavigation = false
// 监听链接点击
document.addEventListener('click', (e) => {
  if (e.target.tagName === 'A' && new URL(e.target.href).origin === window.location.origin) {
    isActiveNavigation = true
  }
})
// 监听表单提交
document.addEventListener('submit', () => {
  isActiveNavigation = true
})

// beforeunload里判断类型
window.addEventListener('beforeunload', () => {
  if (isActiveNavigation) {
    // 主动跳转场景逻辑
  }
})

内容的提问来源于stack exchange,提问作者Loren

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 16:30:01