如何判断用户是否离开了当前页面?

云游道人 2025-06-26 575 阅读 0评论

在现代 Web 开发中,我们常常需要知道用户是否还停留在当前页面。这个看似简单的需求,背后却关联着用户体验、数据分析和系统性能等多个重要方面。

“离开页面”这个行为本身可以被细分为多种场景:

  1. 切换到其他浏览器标签页或应用(页面变为不可见,但未关闭)。

  2. 最小化浏览器窗口(同上)。

  3. 关闭浏览器标签页或整个浏览器

  4. 在当前标签页中导航到新的 URL

  5. 在移动设备上切换到其他 App 或返回主屏幕

针对这些不同的场景,前端提供了多种不同的技术和 API 来进行判断。

方法一:Page Visibility API (页面可见性 API) - 现代首选

这是处理“页面是否对用户可见”这一问题的标准方法。它专门用于检测页面是否被隐藏或显示,非常适合处理用户切换标签页、最小化窗口等场景。

核心概念:

  • document.hidden:一个只读属性,如果页面处于后台或最小化状态,则返回 true,否则返回 false

  • visibilitychange 事件:当页面的可见性状态发生变化时(即 document.hidden 的值改变时),该事件会在 document 对象上触发。

适用场景:

  • 暂停/播放视频或音频。

  • 停止/启动动画或轮播图。

  • 暂停轮询服务器请求,在页面恢复可见时再继续。

代码示例:

document.addEventListener('visibilitychange', () => {
  if (document.hidden) {
    // 页面变得不可见
    console.log('用户离开了当前页面(切换标签页或最小化)');
    // 在这里暂停视频、动画等
    pauseMyVideo();
  } else {
    // 页面恢复可见
    console.log('用户回到了当前页面');
    // 在这里恢复播放
    playMyVideo();
  }
});

优点:

  • 标准、可靠:W3C 标准,所有现代浏览器都支持。

  • 性能友好:专门为此设计,能有效节省 CPU 和电池资源。

  • 逻辑清晰:直接反映页面的“可见”状态。

缺点:

  • 它无法判断用户是否正在关闭页面。当用户关闭标签页时,visibilitychange 事件可能会触发(变为 hidden),但我们无法区分这是切换还是关闭。


方法二:beforeunload 和 unload 事件 - 传统告别方式

这两个事件是在用户即将真正离开页面(关闭、刷新、导航到其他链接)时触发的。

1. beforeunload 事件

该事件在窗口、文档及其资源即将被卸载时触发。它可以用来询问用户是否确定要离开。

核心用途:

  • 防止用户意外丢失未保存的数据。浏览器通常会弹出一个确认对话框。

代码示例:

window.addEventListener('beforeunload', (event) => {
 // 为了兼容性,必须设置 returnValue
 // 现代浏览器会忽略我们设置的字符串,只显示标准提示信息
 event.returnValue = '您有未保存的更改,确定要离开吗?'; 
 // 或者使用 preventDefault()
 // event.preventDefault();

});

注意:出于安全考虑,现代浏览器不允许开发者自定义提示框中的文本内容,只会显示浏览器内置的标准化提示。

2. unload 事件

该事件在页面已经开始卸载之后触发。这是我们在用户离开时执行最后清理操作的传统位置。

代码示例:

window.addEventListener('unload', () => {
  console.log('用户正在关闭或离开页面');
  // 警告:在这里执行的操作可能不会完成!
  // sendAnalyticsData();
});

重大缺陷:
unload 事件非常不可靠。浏览器在处理页面卸载时,并不会等待 unload 事件处理器中的异步操作(如 fetch 或 XMLHttpRequest)完成。这意味着,如果我们想在这里发送一个分析数据到服务器,这个请求很可能在发送完成之前就被浏览器终止了。


方法三:navigator.sendBeacon() - 可靠的数据上报利器

为了解决 unload 事件中异步请求不可靠的问题,W3C 推出了 navigator.sendBeacon() API。

核心概念:
sendBeacon() 方法可以异步地向服务器发送少量数据,并且浏览器保证会将其启动并排队发送,而不会阻塞或延迟页面的卸载过程。即使页面已经关闭,数据发送也会在后台继续进行。

适用场景:

  • 在用户离开页面时,可靠地发送日志、分析或统计数据。

如何使用(通常与 unload 或 pagehide 结合):

window.addEventListener('unload', (event) => {
 const data = {userId:'123',duration: 300 };
 const blob = new Blob([JSON.stringify(data)],{ype: 'application/json; charset=URF-8'});
 // 使用 sendBeacon 发送数据
 // URL 是我们的服务器接收数据的端点
 navigator.sendBeacon('/log',blob);
 console.log('已通过 Beacon API 发送数据');
});

这种方式是目前在页面卸载时发送数据的最佳实践


方法四:pagehide 和 pageshow 事件 - 应对往返缓存(bfcache)

现代浏览器(尤其是移动端)引入了“往返缓存”(Back-Forward Cache, bfcache)。当用户导航到其他页面后,如果点击“后退”按钮,浏览器可能会直接从缓存中恢复上一个页面,而不是重新加载它。在这种情况下,unload 事件可能根本不会触发。

pagehide 事件则可以更好地处理这种情况。

核心概念:

  • pagehide 事件:在用户导航离开页面时触发,无论页面是否被存入 bfcache。

  • event.persistedpagehide 事件对象的一个属性。如果页面被存入 bfcache,它为 true;否则为 false

代码示例:

window.addEventListener('pagehide', (event) => {
  if (event.persisted) {
    console.log('页面正在进入 bfcache');
  } else {
    console.log('页面正在被正常卸载');
  }

  // 无论哪种情况,这里都是发送 Beacon 的好时机
  navigator.sendBeacon('/log', getAnalyticsData());
});

pagehide 比 unload 更可靠,特别是在移动设备上。因此,推荐使用 pagehide 来代替 unload

最终建议

  1. 对于“可见性”判断:优先使用 Page Visibility API

  2. 对于“离开时上报数据”:使用 navigator.sendBeacon(),并将其放在 pagehide 事件监听器中,以获得最佳的兼容性和可靠性。

  3. 对于“防止数据丢失”:仅在必要时使用 beforeunload,因为它会中断用户操作。

  4. 避免使用 unload:除非我们只需要执行一些非常简单的同步代码,否则尽量避免使用它,尤其不要在其中包含异步网络请求。

通过组合运用这些现代 API,我们不仅能准确地判断用户的行为,还能在不牺牲性能和可靠性的前提下,打造出更智能、更友好的用户体验。

喜欢就支持以下吧
点赞 0

发表评论

快捷回复: 表情:
aoman baiyan bishi bizui cahan ciya dabing daku deyi doge fadai fanu fendou ganga guzhang haixiu hanxiao zuohengheng zhuakuang zhouma zhemo zhayanjian zaijian yun youhengheng yiwen yinxian xu xieyanxiao xiaoku xiaojiujie xia wunai wozuimei weixiao weiqu tuosai tu touxiao tiaopi shui se saorao qiudale qinqin qiaoda piezui penxue nanguo liulei liuhan lenghan leiben kun kuaikule ku koubi kelian keai jingya jingxi jingkong jie huaixiao haqian aini OK qiang quantou shengli woshou gouyin baoquan aixin bangbangtang xiaoyanger xigua hexie pijiu lanqiu juhua hecai haobang caidao baojin chi dan kulou shuai shouqiang yangtuo youling
提交
评论列表 (有 0 条评论, 575人围观)

最近发表

热门文章

最新留言

热门推荐

标签列表