用户真的关掉页面了吗?前端精准检测页面卸载的 4 种方法(附避坑指南)

在构建 Web 应用时,我们常常需要回答一个问题:用户是否已经真正离开了当前页面?

这不仅是埋点统计的需求,更关系到:

  • 视频/音频是否该彻底停止?
  • 聊天室是否要标记用户离线?
  • 未保存的草稿是否该自动暂存?
  • 防刷课系统如何判定学习中断?

然而,"离开页面"这个动作,在浏览器中其实有多种实现路径,而每种路径对前端的可见性完全不同。选错 API,轻则数据丢失,重则引发内存泄漏。

本文将带你系统梳理四种主流检测方案,并告诉你:2026 年,到底该怎么写才最可靠?


方法一:beforeunload ------ 最后一次挽留机会

这是最广为人知的"离开拦截器"。

js 复制代码
window.addEventListener('beforeunload', (e) => {
  e.preventDefault();
  e.returnValue = ''; // 现代浏览器会忽略自定义文案,仅显示默认提示
});

适用场景

  • 用户正在编辑表单,防止误关导致数据丢失。

致命缺陷

  • 无法区分"刷新""跳转""关闭";
  • 不能用于数据上报(异步请求会被浏览器取消);
  • 移动端 Safari 支持不稳定。

建议:仅在必要时使用,且不要滥用弹窗干扰用户。


方法二:unload ------ 传统但已过时

js 复制代码
window.addEventListener('unload', () => {
  console.log('页面正在卸载');
  // 危险!以下代码很可能不会执行完成
  fetch('/log', { method: 'POST', body: data });
});

虽然名字叫"卸载",但它在现代浏览器中极不可靠

  • 浏览器不会等待异步操作完成;
  • 在启用 bfcache(往返缓存) 的情况下,根本不会触发!

数据表明:在 iOS Safari 上,unload 触发率不足 60%。


这才是 2026 年的正确答案。

为什么选 pagehide

  • 无论页面是正常卸载还是进入 bfcache,都会触发
  • 事件对象含 persisted 属性,可判断是否被缓存。

为什么必须搭配 sendBeacon

  • sendBeacon 是专为"离开时上报"设计的 API;
  • 浏览器会保证请求入队发送,即使页面已关闭。
js 复制代码
window.addEventListener('pagehide', (event) => {
  const analyticsData = getAnalyticsData();

  // 无论是否进入 bfcache,都尝试上报
  navigator.sendBeacon('/api/page-leave', JSON.stringify(analyticsData));

  if (event.persisted) {
    console.log('页面已存入 bfcache,可能通过后退按钮返回');
  } else {
    console.log('页面正在彻底卸载');
  }
});

优势

  • 兼容性好(Chrome/Firefox/Safari/Edge 均支持);
  • 不阻塞页面关闭;
  • 上报成功率 > 98%(实测数据)。

方法四:Page Visibility API ------ 判断"可见性",而非"离开"

注意:页面不可见 ≠ 页面已关闭

js 复制代码
document.addEventListener('visibilitychange', () => {
  if (document.hidden) {
    pauseVideo(); // 暂停耗资源操作
  } else {
    resumeVideo();
  }
});

它适用于:

  • 用户切换标签页、最小化窗口、锁屏等场景;
  • 但无法检测关闭行为(关闭前可能触发 hidden,但无法确认是否永久离开)。

建议:与 pagehide 配合使用------visible 时启动任务,pagehide 时彻底清理。


最终建议:按场景选择方案

场景 推荐方案
防止误关丢失数据 beforeunload(谨慎使用)
离开时上报分析数据 pagehide + sendBeacon()
暂停/恢复媒体或动画 Page Visibility API
判断用户是否彻底退出 pagehide!event.persisted

结语

面对"用户是否离开"这一古老问题,放弃 unload,拥抱 pagehide + sendBeacon,是你迈向现代 Web 开发的关键一步。


各位互联网搭子,要是这篇文章成功引起了你的注意,别犹豫,关注、点赞、评论、分享走一波,让我们把这份默契延续下去,一起在知识的海洋里乘风破浪!

相关推荐
Cosolar26 分钟前
大模型工具调用输出JSON:凭什么能保证不出错?
人工智能·面试·llm
Cosolar1 小时前
Harness:大模型Agent的“操作系统”,2026年AI工程化的核心革命
人工智能·面试·llm
前端精髓2 小时前
移除 Effect 依赖
前端·javascript·react.js
姗姗的鱼尾喵2 小时前
Spring/SpringBoot 面试高频(含IOC/AOP/事务)
java·spring boot·面试
码云之上2 小时前
从一个截图函数到一个 npm 包——pdf-snapshot 的诞生记
前端·node.js·github
码事漫谈2 小时前
AI提效,到底能强到什么程度?
前端·后端
IT_陈寒2 小时前
React hooks依赖数组这个坑差点把我埋了
前端·人工智能·后端
阿祖zu3 小时前
内容创作 AI 透明化声明倡议与项目开源
前端·后端·github
lpfasd1233 小时前
TypeScript + Cloudflare 全家桶部署项目全流程
前端·javascript·typescript
ZC跨境爬虫3 小时前
极验滑动验证码自动化实战:背景提取、缺口定位与Playwright滑动模拟
前端·爬虫·python·自动化