在现代 Web 开发中,我们常常需要知道用户是否还停留在当前页面。这个看似简单的需求,背后却关联着用户体验、数据分析和系统性能等多个重要方面。
“离开页面”这个行为本身可以被细分为多种场景:
切换到其他浏览器标签页或应用(页面变为不可见,但未关闭)。
最小化浏览器窗口(同上)。
关闭浏览器标签页或整个浏览器。
在当前标签页中导航到新的 URL。
在移动设备上切换到其他 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.persisted:pagehide事件对象的一个属性。如果页面被存入 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。
最终建议
对于“可见性”判断:优先使用 Page Visibility API。
对于“离开时上报数据”:使用
navigator.sendBeacon(),并将其放在pagehide事件监听器中,以获得最佳的兼容性和可靠性。对于“防止数据丢失”:仅在必要时使用
beforeunload,因为它会中断用户操作。避免使用
unload:除非我们只需要执行一些非常简单的同步代码,否则尽量避免使用它,尤其不要在其中包含异步网络请求。
通过组合运用这些现代 API,我们不仅能准确地判断用户的行为,还能在不牺牲性能和可靠性的前提下,打造出更智能、更友好的用户体验。
匿名
2025-11-09
https://collaigo.com 免费在线拼图工具
匿名
2025-10-22
盖楼盖楼!
匿名
2025-08-11
沙发沙发
匿名
2025-08-10
https://at.oiik.cn/bing.html
匿名
2025-02-21
实用,我在开发https://minmail.app/时候使用到了
王飞翔
2024-12-30
亲爱的朋友:您好!中国疫情持续蔓延,很多人症状非常严重持久不愈,医院人满为患,各年龄段随地倒猝死的现象暴增,多省感染手足口、甲流、乙流、支原体、合胞及腺病毒的儿童不断攀升,目前各种天灾人祸,天气异象频发。古今中外的很多预言都说了这几年人类有大灾难,如刘伯温在预言中说 “贫者一万留一千,富者一万留二三”,“贫富若不回心转,看看死期到眼前”, 预言中也告诉世人如何逃离劫难的方法,真心希望您能躲过末劫中的劫难,有个美好的未来,请您务必打开下方网址认真了解,内有躲避瘟疫保平安的方法。网址1:https://github.com/1992513/www/blob/master/README.md?abhgc#1 网址2:bitly.net/55bbbb 网址3:https://d3ankibxiji86m.cloudfront.net/30gj 如打不开请多换几个浏览器试