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


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

相关推荐
yangyanping201082 小时前
Vue入门到精通七之关键字const
前端·javascript·vue.js
姝然_95272 小时前
Jetpack Compose 绘制流程与自定义布局
前端
lxh01132 小时前
重复的DNA序列
开发语言·javascript·ecmascript
姝然_95272 小时前
Jetpack Compose Brush 渐变
前端
重庆小透明2 小时前
【面试问题第一篇】快手后端java一面
java·面试·职场和发展
阿鑫_9962 小时前
通用-ESLint+Prettier基础知识
前端·后端
ai超级个体2 小时前
金三银四,一个面试官连连夸赞的个人网页技术分享
前端·面试·three.js·threejs·网页设计·网页灵感·网页分享
Oneslide2 小时前
块级元素竖向堆叠且宽度默认会撑满其父容器的可用宽度
前端
i建模2 小时前
npm使用大全
前端·npm·node.js