我试图找出用户何时离开指定页面。找到他在页面内部使用链接导航时没有问题,但我需要标记一些内容,例如当他关闭窗口或输入另一个URL并按下回车时。第二个不是那么重要,但第一个是。所以这是一个问题:
如何查看用户何时关闭我的页面(捕获window.close事件),然后......并不重要(我需要发送一个AJAX请求,但是如果我可以让它运行警报,我可以做其余的事。)
答案 0 :(得分:31)
有unload
和beforeunload
个javascript事件,但这些事件对于Ajax请求并不可靠(不能保证在其中一个事件中启动的请求会到达服务器)。
因此,这样做非常不推荐,您应该寻找替代方案。
如果您确实需要这个,请考虑使用“ping”式解决方案。每分钟发送一个请求,基本上告诉服务器“我还在这里”。然后,如果服务器超过两分钟没有收到此类请求(您必须考虑延迟等),则认为客户端处于脱机状态。
另一种解决方案是使用unload
或beforeunload
来执行Sjax请求(同步JavaScript和XML),但完全不建议这样做。这样做基本上会冻结用户的浏览器,直到请求完成,这是他们不喜欢的(即使请求花费的时间很少)。
答案 1 :(得分:17)
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);
});
似乎还有polyfill for sendBeacon。如果方法本身不可用,它会转向发送同步AJAX。
移动设备的重要事项:请注意,不保证会为手机触发卸载事件处理程序。但是保证 visibilitychange 事件被触发。因此,对于移动设备,您的数据收集代码可能需要进行一些调整。
您可以参考我的blog article获取所有3种方式的代码实现。
答案 2 :(得分:14)
基于other answer。
为了说清楚,2018年,Beacon API是此问题的解决方案(在almost every browser上)
保证在卸载页面之前启动信标请求 它们运行完成,无需阻止请求。
您可以在onunload
事件中使用它,并确信它会被发送。
$(window).on('unload', function() {
var URL = "https://example.com/foo";
var data = "bar";
navigator.sendBeacon(URL, data);
});
很棒的博文:http://usefulangle.com/post/62/javascript-send-data-to-server-on-page-exit-reload-redirect
Beacon API:https://developer.mozilla.org/en-US/docs/Web/API/Beacon_API/Using_the_Beacon_API
答案 3 :(得分:3)
我也希望实现相同的功能和来自Felix的回答( 无法保证在其中一个事件中启动的请求将到达服务器 )。
要使请求到达服务器,我们在下面尝试了代码: -
onbeforeunload = function() {
//Your code goes here.
return "";
}
我们正在使用IE浏览器&现在,当用户关闭浏览器时,由于return "";
&等待用户的确认&此等待时间使请求到达服务器。
答案 4 :(得分:1)
发布问题几年后,我做了一个更好的实现,包括nodejs和socket.io(https://socket.io)(您可以使用任何类型的套接字,但这是我个人的选择)。
基本上,我打开了与客户端的连接,当它挂断时,我只是保存数据/做我需要的任何事情。显然,这不能用于显示任何内容/重定向客户端(因为您正在服务器端进行操作),但这是我当时真正需要的。
io.on('connection', function(socket){
socket.on('disconnect', function(){
// Do stuff here
});
});
所以...如今,我认为这会更好(尽管更难实现,因为您需要节点,套接字等,但并不那么困难;如果您第一次进行,大约需要30分钟)而不是卸载版本。
答案 5 :(得分:0)
我同意Felix的想法,我已经用该解决方案解决了我的问题,现在我想清除服务器端解决方案:
1.从客户端向服务器发送请求
2.在变量中收到的最后一次请求的保存时间
3.检查服务器时间并将其与上次收到的变量进行比较 请求
4.如果结果超出预期,请开始运行 Windows关闭时要运行的代码...
答案 6 :(得分:0)
所选答案是正确的,您无法保证浏览器发送xhr请求,但根据浏览器的不同,您可以在选项卡或窗口关闭时可靠地发送请求。
通常,浏览器在xhr.send()实际执行之前关闭。 Chrome和Edge看起来像是在关闭窗口之前等待javascript事件循环清空。他们还在与javascript事件循环不同的线程中触发xhr请求。这意味着如果您可以将事件循环保持足够长时间,则xhr将成功触发。例如,我测试了发送xhr请求,然后计数到100,000,000。对于我来说,这在chrome和edge中都非常一致。如果你正在使用angularjs,那么在$ apply中将你的调用包装成$ http就可以完成同样的事情。
IE似乎有点不同。我不认为IE等待事件循环为空,或者甚至是当前堆栈帧为空。虽然它偶尔会正确地发送请求,但似乎更常见的事情(80%-90%的时间)是IE将在xhr请求完全执行之前关闭窗口或选项卡,这导致只有部分消息被送了。基本上服务器收到一个帖子请求,但没有正文。对于后人,这里我使用的代码作为window.onbeforeunload侦听器函数附加:
var xhr = new XMLHttpRequest();
xhr.open("POST", <your url here>);
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
var payload = {id: "123456789"};
xhr.send(JSON.stringify(payload));
for(var i = 0; i < 100000000; i++) {}
我测试过:
Chrome 61.0.3163.100
IE 11.608.15063.0CO
Edge 40.15063.0.0
答案 7 :(得分:0)
尝试这个。我用javascript解决了这个问题,在浏览或关闭标签页时向服务器发送了ajax调用。我在刷新页面时遇到问题,因为onbeforeunload函数包括刷新页面。 performance.navigation.type == 1应该将刷新与关闭(在Mozzila浏览器上)隔离。
$(window).bind('mouseover', (function () { // detecting DOM elements
window.onbeforeunload = null;
}));
$(window).bind('mouseout', (function () { //Detecting event out of DOM
window.onbeforeunload = ConfirmLeave;
}));
function ConfirmLeave() {
if (performance.navigation.type == 1) { //detecting refresh page(doesnt work on every browser)
}
else {
logOutUser();
}
}
$(document).bind('keydown', function (e) { //detecting alt+F4 closing
if (e.altKey && e.keyCode == 115) {
logOutUser();
}
});
function logOutUser() {
$.ajax({
type: "POST",
url: GWA("LogIn/ForcedClosing"), //example controller/method
async: false
});
}
答案 8 :(得分:-3)
使用:
<body onUnload="javascript:">
除了关闭浏览器程序外,它应该捕获所有内容。