我试图找出用户何时离开指定页面。找出他何时使用页面内的链接导航离开没有问题,但我需要标记一些内容,例如他关闭窗口或键入另一个 URL 并按下 Enter 键。第二个不是那么重要,但第一个很重要。那么问题来了:
我如何才能看到用户何时关闭了我的页面(捕获 window.close 事件),然后...并不重要(我需要发送 AJAX 请求,但如果我可以让它运行警报,我可以做剩下的)。
我试图找出用户何时离开指定页面。找出他何时使用页面内的链接导航离开没有问题,但我需要标记一些内容,例如他关闭窗口或键入另一个 URL 并按下 Enter 键。第二个不是那么重要,但第一个很重要。那么问题来了:
我如何才能看到用户何时关闭了我的页面(捕获 window.close 事件),然后...并不重要(我需要发送 AJAX 请求,但如果我可以让它运行警报,我可以做剩下的)。
Beacon API是这个问题的解决方案(几乎在每个浏览器上)。
即使用户退出页面,信标请求也应该完成。
你应该什么时候触发你的 Beacon 请求?
这将取决于您的用例。如果您想捕获任何用户退出,visibilitychange
(not unload
) 是开发人员在现代浏览器中可以可靠观察到的最后一个事件。
注意:只要实施的visibilitychange
是不同的浏览器并不一致,很容易通过检测到它lifecycle.js库。
# lifecycle.js (1K) for cross-browser compatibility
# https://github.com/GoogleChromeLabs/page-lifecycle
<script defer src="/path/to/lifecycle.js"></script>
<script defer>
lifecycle.addEventListener('statechange', function(event) {
if (event.originalEvent == 'visibilitychange' && event.newState == 'hidden') {
var URL = "https://example.com/foo";
var data = "bar";
navigator.sendBeacon(URL, data);
}
});
</script>
即使用户离开页面 - 切换到另一个应用程序等 -信标请求也应该运行完成,而不会阻止用户工作流程。
var URL = "https://example.com/foo";
var data = "bar";
navigator.sendBeacon(URL, data);
问题是何时发送您的 Beacon 请求。特别是如果您想等到最后一刻发送会话信息、分析等。
在unload
活动期间发送它曾经是一种常见的做法,但是页面生命周期管理的变化 - 由移动用户体验驱动 - 扼杀了这种方法。今天,大多数移动工作流程(切换到新选项卡、切换到主屏幕、切换到另一个应用程序......)在任何时候都不会触发该unload
事件。
如果您想在用户退出您的应用程序/页面时执行某些操作,现在建议使用该visibilitychange
事件并检查从passive
tohidden
状态的转换。
document.addEventListener('visibilitychange', function() {
if (document.visibilityState == 'hidden') {
// send beacon request
}
});
向隐藏的转换通常是开发人员可以可靠观察到的最后一个状态更改(在移动设备上尤其如此,因为用户可以关闭选项卡或浏览器应用程序本身,并且在这些情况下不会触发 beforeunload、pagehide 和 unload 事件) .
这意味着您应该将隐藏状态视为用户会话的可能结束。换句话说,保留任何未保存的应用程序状态并发送任何未发送的分析数据。
在这篇文章Page lifecyle API
中解释了详细信息。
然而,visibilitychange
事件的实现,以及 Page lifecycle API
跨浏览器的不一致。
在浏览器实现赶上之前,使用生命周期.js库和页面生命周期最佳实践似乎是一个很好的解决方案。
# lifecycle.js (1K) for cross-browser compatibility
# https://github.com/GoogleChromeLabs/page-lifecycle
<script defer src="/path/to/lifecycle.js"></script>
<script defer>
lifecycle.addEventListener('statechange', function(event) {
if (event.originalEvent == 'visibilitychange' && event.newState == 'hidden') {
var URL = "https://example.com/foo";
var data = "bar";
navigator.sendBeacon(URL, data);
}
});
</script>
有关 vanilla 页面生命周期事件的可靠性的更多数字(没有lifecycle.js),还有这个研究。
有unload
和beforeunload
javascript 事件,但这些对于 Ajax 请求是不可靠的(不能保证在这些事件之一中发起的请求会到达服务器)。
因此,强烈不建议这样做,您应该寻找替代方法。
如果您确实需要这个,请考虑“ping”风格的解决方案。每分钟发送一个请求,基本上是告诉服务器“我还在这里”。然后,如果服务器超过两分钟没有收到这样的请求(你必须考虑延迟等),你认为客户端离线。
另一种解决方案是使用unload
或beforeunload
执行 Sjax 请求(同步 JavaScript 和 XML),但完全不推荐这样做。这样做基本上会冻结用户的浏览器,直到请求完成,这是他们不会喜欢的(即使请求花费的时间很少)。
1) 如果您正在寻找一种可以在所有浏览器中工作的方法,那么最安全的方法是向服务器发送同步 AJAX。这不是一个好方法,但至少要确保您没有向服务器发送太多数据,并且服务器速度很快。
2) 您也可以使用异步 AJAX 请求,并在服务器上使用ignore_user_abort函数(如果您使用的是 PHP)。然而ignore_user_abort 在很大程度上取决于服务器配置。确保你测试得很好。
3) 对于现代浏览器,您不应发送 AJAX 请求。您应该使用新的navigator.sendBeacon方法将数据异步发送到服务器,并且不会阻塞下一页的加载。由于您希望在用户移出页面之前将数据发送到服务器,因此您可以在卸载事件处理程序中使用此方法。
$(window).on('unload', function() {
var fd = new FormData();
fd.append('ajax_data', 22);
navigator.sendBeacon('ajax.php', fd);
});
sendBeacon似乎也有一个polyfill。如果方法本身不可用,它会求助于发送同步 AJAX。
移动设备的重要信息:请注意,不保证为移动设备触发卸载事件处理程序。但是visibilitychange事件肯定会被触发。因此,对于移动设备,您的数据收集代码可能需要进行一些调整。
3种方式的代码实现可以参考我的博客文章。
我也想实现相同的功能并从 Felix那里找到了这个答案(不能保证在这些事件之一中发起的请求会到达服务器)。
为了使请求到达服务器,我们尝试了以下代码:-
onbeforeunload = function() {
//Your code goes here.
return "";
}
我们正在使用 IE 浏览器 & 现在当用户关闭浏览器时,他会收到确认对话框,因为return "";
& 等待用户的确认 & 这个等待时间使请求到达服务器。
发布问题多年后,我做了一个更好的实现,包括 nodejs 和 socket.io ( https://socket.io )(你可以使用任何类型的套接字,但这是我个人的选择)。
基本上我打开与客户端的连接,当它挂断时,我只是保存数据/做我需要的任何事情。显然,这不能用于显示任何内容/重定向客户端(因为您在服务器端这样做),但当时我真正需要的是。
io.on('connection', function(socket){
socket.on('disconnect', function(){
// Do stuff here
});
});
所以......现在我认为这会是一种比卸载版本。