当我们刷新页面(F5,或浏览器中的图标)时,它会首先触发 ONUNLOAD 事件。当我们关闭浏览器(右上角的 X 图标)时,它会触发 ONUNLOAD 事件。现在触发 ONUNLOAD 事件时,无法区分刷新页面或关闭浏览器。如果您有任何解决方案,请给我。
识别刷新和关闭浏览器操作
有一个解决方案。
我想在选项卡或浏览器窗口关闭时断开服务器上的用户连接,而不是在重新加载页面时断开连接(您可能希望出于不同目的区分重新加载/关闭事件,但您可能会从我的解决方案中受益)。基于 HTML5 的本地存储和客户端/服务器 AJAX 通信,我最终完成了以下过程:
您的网页上,添加
onunload
到window
下面的处理程序(伪的JavaScript):function myUnload(event) { if (window.localStorage) { // flag the page as being unloading window.localStorage['myUnloadEventFlag']=new Date().getTime(); } // notify the server that we want to disconnect the user in a few seconds (I used 5 seconds) askServerToDisconnectUserInAFewSeconds(); // synchronous AJAX call }
在您的页面
onload
上,body
向以下处理程序(伪 javascript)添加 :function myLoad(event) { if (window.localStorage) { var t0 = Number(window.localStorage['myUnloadEventFlag']); if (isNaN(t0)) t0=0; var t1=new Date().getTime(); var duration=t1-t0; if (duration<10*1000) { // less than 10 seconds since the previous Unload event => it's a browser reload (so cancel the disconnection request) askServerToCancelDisconnectionRequest(); // asynchronous AJAX call } else { // last unload event was for a tab/window close => do whatever you want (I do nothing here) } } }
在服务器上,收集列表中的断开连接请求,并设置一个定时线程,定期检查列表(我每 20 秒使用一次)。一旦断开连接请求超时(即 5 秒消失),断开用户与服务器的连接。如果同时接收到断线请求取消,则将相应的断线请求从列表中移除,这样用户就不会被断线。
如果您想区分选项卡/窗口关闭事件和跟踪链接或提交的表单,则此方法也适用。您只需要在包含链接和表单的每个页面以及每个链接/表单登录页面上放置两个事件处理程序。
请注意,我使用unload
事件而不是beforeUnload
事件来正确管理附件链接:当用户单击附件链接(例如 PDF 文件)时,将beforeUnload
调度该事件,然后引发打开/保存弹出窗口,并且仅此而已(浏览器不会更改显示的页面并且不会调度unload
事件)。如果我正在使用该beforeUnload
事件(就像我以前所做的那样),我会在没有页面更改时检测到页面更改。
此方法仅限于支持 HTML5 本地存储的浏览器,因此您可能会对旧浏览器(如 MSIE7)使用特定方法。
其他基于 的event.clientY
方法不可靠,因为在单击重新加载或选项卡/窗口关闭按钮时该值是负值,而当使用键盘快捷键重新加载(例如 F5、Ctrl-R、...)和窗口关闭时,该值是正值(例如 Alt-F4)。依赖事件 X 位置也不可靠,因为按钮在每个浏览器上的位置不同(例如左侧的关闭按钮)。
不幸的是,正如这里的一些答案所建议的那样,检查事件的clientY
/pageY
值并不是确定unload
事件是否因用户关闭页面而被触发的可靠方法。
单击浏览器的关闭按钮时clientY
/pageY
为负的原因是因为关闭按钮位于文档顶部上方(即像素 0 上方),但重新加载按钮也是如此,这意味着单击重新加载按钮也会导致负clientY
/ 的值pageY
。
沿着检查事件的 x 坐标的路径也有问题,因为浏览器关闭按钮并不总是在窗口的右侧(例如,它在 OS X 中位于左侧)并且因为可以关闭窗口通过关闭其选项卡或通过键盘。
也许有人还在寻找答案......
您可以为此使用SessionStorage!SessionStorage不会在页面重新加载时清除,而是在关闭时清除。所以基本上你可以在页面加载时设置一个键/值对,但在此之前你检查键/值对是否存在。如果确实存在,则表示该页面已重新加载,否则表示用户第一次或在新选项卡中打开了该页面。
if (sessionStorage.getItem('reloaded') != null) {
console.log('page was reloaded');
} else {
console.log('page was not reloaded');
}
sessionStorage.setItem('reloaded', 'yes');
通过这种方式,您可以doStuff()
使用onunload
事件(用户离开页面),并且otherStuff()
设置键/值对(用户重新加载页面)。
这是一个有一些限制的巨大黑客,但它在大多数实际情况下都有效。
因此,如果您只需要在用户使用ctrl
+r
或cmd
+r
快捷方式时起作用的东西,您可以跟踪r
在重新加载/关闭时需要执行的任何操作时是否按下。
只需创建keydown
和keyup
事件侦听器来切换rDown
变量。
let rDown = false;
window.addEventListener("keydown", event => {
if (event.key == 'r')
rDown = true;
})
window.addEventListener("keyup", event => {
if (event.key == 'r')
rDown = false;
})
然后你有你的“onunload”事件监听器,监听器函数有一个if
检查 if rDown
is的语句true
。
window.addEventListener("onunload", () => {
if (!rDown) {
// code that only gets run when the window is closed (or
// some psychopath reloads by actually clicking the icon)
}
});
今天我遇到了同样的问题,并找到了一个可能的解决方案,我想与您分享。
在思考什么有助于区分刷新和关闭时,我想到了 cookie。我记得设置一个没有明确过期日期的 cookie 会使其仅对当前会话可用。并且当前会话在浏览器关闭之前显然有效。这不包括关闭选项卡,但我的问题是关于用户身份验证,我不想仅因为关闭选项卡而注销用户(我认为这ASPXAUTH
与 ASP.NET的cookie 的方法相同)。
因此,document.cookies
当用户登录并在页面加载时检查它时,我在集合中放置了一个简单的 cookie :如果 cookie 仍然存在,则它是刷新或重新打开的选项卡并保留用户数据,如果 cookie 不存在会话已过期,因此用户数据已清除(与显式注销相同)。
希望这种方法对其他人有用!