用户真的关掉页面了吗?前端精准检测页面卸载的 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 开发的关键一步。


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

相关推荐
福兮说8 小时前
前端下载大文件,点了按钮半天没反应:fetch + blob 的三个问题和三种替代写法
前端·javascript·性能优化·文件下载
GreenTea8 小时前
我把 Agent 的 while 循环拆掉了:一种你可能没想到的 Agent 架构
前端·后端·架构
科技观察哨8 小时前
六足平台选型与纳米定位系统集成:HEB-640六自由度位移台在半导体光刻对准中的参数边界与国产替代评估
前端·人工智能
niucloud-admin8 小时前
JAVA V6 多商户商城 开发文档——web前端
前端
颜进强9 小时前
16 · NestJS LifecycleEvents 生命周期事件:五个钩子、三条边界,和 rag-server 的优雅停机
前端·后端·ai编程
今年下半年10 小时前
【VUE】整合腾讯地图、自定义区域边界、村委名称及资产统计(放大显示资产点位)
前端·javascript·vue.js
郑州光合科技余经理10 小时前
同城电商系统:库存变更怎么同步到订单
java·开发语言·前端·后端·uni-app·php·ai编程
我叫黑大帅10 小时前
Go日志库工程选型与逃逸分析评测报告
后端·面试·go
此时不提桶,更待何时12 小时前
05-05-B-对象存储与文件服务面试与生产事故实战
面试·nosql
前端snow12 小时前
ai agent --- DeepAgents 中间件
前端