识别刷新和关闭浏览器操作

IT技术 javascript browser
2021-01-19 18:52:31

当我们刷新页面(F5,或浏览器中的图标)时,它会首先触发 ONUNLOAD 事件。当我们关闭浏览器(右上角的 X 图标)时,它会触发 ONUNLOAD 事件。现在触发 ONUNLOAD 事件时,无法区分刷新页面或关闭浏览器。如果您有任何解决方案,请给我。

6个回答

有一个解决方案。

我想在选项卡或浏览器窗口关闭时断开服务器上的用户连接,而不是在重新加载页面时断开连接(您可能希望出于不同目的区分重新加载/关闭事件,但您可能会从我的解决方案中受益)。基于 HTML5 的本地存储和客户端/服务器 AJAX 通信,我最终完成了以下过程:

  1. 您的网页上,添加onunloadwindow下面的处理程序(伪的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
    }
    
  2. 在您的页面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)
            }
        }
    } 
    
  3. 在服务器上,收集列表中的断开连接请求,并设置一个定时线程,定期检查列表(我每 20 秒使用一次)。一旦断开连接请求超时(即 5 秒消失),断开用户与服务器的连接。如果同时接收到断线请求取消,则将相应的断线请求从列表中移除,这样用户就不会被断线。

如果您想区分选项卡/窗口关闭事件和跟踪链接或提交的表单,则此方法也适用。您只需要在包含链接和表单的每个页面以及每个链接/表单登录页面上放置两个事件处理程序。

请注意,我使用unload事件而不是beforeUnload事件来正确管理附件链接:当用户单击附件链接(例如 PDF 文件)时,将beforeUnload调度事件,然后引发打开/保存弹出窗口,并且仅此而已(浏览器不会更改显示的页面并且不会调度unload事件)。如果我正在使用该beforeUnload事件(就像我以前所做的那样),我会在没有页面更改时检测到页面更改。

此方法仅限于支持 HTML5 本地存储的浏览器,因此您可能会对旧浏览器(如 MSIE7)使用特定方法。

其他基于 的event.clientY方法不可靠,因为在单击重新加载或选项卡/窗口关闭按钮时该值是负值,而当使用键盘快捷键重新加载(例如 F5、Ctrl-R、...)和窗口关闭时,该值是正值(例如 Alt-F4)。依赖事件 X 位置也不可靠,因为按钮在每个浏览器上的位置不同(例如左侧的关闭按钮)。

我会使用sessionStorage而不是localStorage因为您只是在跟踪重新加载,因此没有理由让它持续存在。
2021-03-12 18:52:31
@RajabShakirov 这个答案不适用于在卸载事件期间检测刷新。
2021-04-07 18:52:31
这是如何在现代浏览器中通过 HTML5 api 检测页面重新加载的答案。(对我有用):stackoverflow.com/questions/5004978/...
2021-04-08 18:52:31
什么是askServerToDisconnectUserInAFewSeconds
2021-04-10 18:52:31
@Kiquenet:这是对服务器的请求,要求取消在步骤 1 中发送的断开连接请求。
2021-04-10 18:52:31

不幸的是,正如这里的一些答案所建议的那样,检查事件clientY/pageY值并不是确定unload事件是否因用户关闭页面而被触发的可靠方法

单击浏览器的关闭按钮时clientY/pageY为负的原因是因为关闭按钮位于文档顶部上方(即像素 0 上方),但重新加载按钮也是如此,这意味着单击重新加载按钮也会导致负clientY/ 的pageY

沿着检查事件的 x 坐标的路径也有问题,因为浏览器关闭按钮并不总是在窗口的右侧(例如,它在 OS X 中位于左侧)并且因为可以关闭窗口通过关闭其选项卡或通过键盘。

也许有人还在寻找答案......

您可以为此使用SessionStorageSessionStorage不会在页面重新加载清除而是在关闭时清除所以基本上你可以在页面加载时设置一个键/值对,但在此之前你检查键/值对是否存在。如果确实存在,则表示该页面已重新加载,否则表示用户第一次或在新选项卡中打开了该页面。

if (sessionStorage.getItem('reloaded') != null) {
    console.log('page was reloaded');
} else {
    console.log('page was not reloaded');
}

sessionStorage.setItem('reloaded', 'yes');

通过这种方式,您可以doStuff()使用onunload事件(用户离开页面),并且otherStuff()设置键/值对(用户重新加载页面)。

这是我尝试成功的方法。如果您认为这是最好的解决方案,请点赞,以便更多人看到。
2021-03-15 18:52:31
就刷新与关闭选项卡/浏览器而言,SessionStorage 似乎是最有前途的。如果您没有浏览器级别的设置,并且您无法要求用户更改设置,则 Cookie 将继续存在。这就是为什么在我看来,SessionStorage 要好得多。@Mointy,感谢您提供此解决方案。
2021-03-22 18:52:31
@MeiLie 这是一个例子:codepen.io/Mointy/pen/oNGgQXx
2021-04-05 18:52:31
我为事件 onunload 尝试了这种方法,但它不起作用。
2021-04-07 18:52:31

这是一个有一些限制巨大黑客,但它在大多数实际情况下都有效。

因此,如果您只需要在用户使用ctrl+rcmd+r快捷方式时起作用的东西,您可以跟踪r在重新加载/关闭时需要执行的任何操作时是否按下。

只需创建keydownkeyup事件侦听器来切换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 rDownis语句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.NETcookie 的方法相同)。

因此,document.cookies当用户登录并在页面加载时检查它时,我在集合中放置了一个简单的 cookie :如果 cookie 仍然存在,则它是刷新或重新打开的选项卡并保留用户数据,如果 cookie 不存在会话已过期,因此用户数据已清除(与显式注销相同)。

希望这种方法对其他人有用!