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

Posted

技术标签:

【中文标题】识别刷新和关闭浏览器操作【英文标题】:Identifying Between Refresh And Close Browser Actions 【发布时间】:2010-10-08 19:29:51 【问题描述】:

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

【问题讨论】:

类似问题请参见:***.com/questions/4387212/… 和 ***.com/questions/1631959/browser-window-close-event 这是如何在现代浏览器中通过 html5 api 检测页面重新加载的答案。(对我有用):***.com/questions/5004978/… 【参考方案1】:

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

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

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


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

这样,您可以使用onunload 事件(用户离开页面)doStuff(),如果设置了键/值对(用户重新加载页面),则可以otherStuff()

【讨论】:

就刷新与关闭选项卡/浏览器而言,SessionStorage 似乎是最有希望的。如果您没有浏览器级别的设置,并且您不能要求用户更改设置,则 Cookie 会持续存在。这就是为什么在我看来,SessionStorage 要好得多。 @Mointy,感谢您的解决方案。 这是我尝试成功的方式。如果您认为这是最好的解决方案,请点赞,让更多人看到。 我尝试过这种方法用于事件 onunload,但它不起作用。 @MeiLie 这里是一个例子:codepen.io/Mointy/pen/oNGgQXx【参考方案2】:

这是一个巨大的技巧,有一些限制,但它适用于大多数实际情况。

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

只需创建切换rDown 变量的keydownkeyup 事件侦听器。

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 语句检查rDown 是否为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)
    
);

【讨论】:

【参考方案3】:

很遗憾,目前还没有建议或可靠的方法。

【讨论】:

【参考方案4】:

归功于https://www.anandkanatt.com/how-do-i-detect-browser-window-closed-refreshed/#comment-15892。我通过使用开瓶器本身进行检查来简化它。在 Chrome 版本 78.0.3887.7 中测试。

你可以试试这个:

添加一个 refresh-close-detector.html 文件。这是示例代码:
<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
      content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Processing...</title>
</head>
<body>

<script>
  if (this.opener) 
    // the opener was refreshed, do something if you want
   else 
    // the opener was closed, do something if you want
  

  // you may want to close the pop up
  this.close()
</script>
</body>
</html>
在要识别刷新和关闭浏览器操作的页面中,添加要卸载的事件侦听器:
window.addEventListener('unload', () => 
  open('refresh-close-detector.html', '', 'width=100,height=100');
)

【讨论】:

【参考方案5】:

这是一个可行的解决方案

export class BootstrapComponent implements OnInit 

  validNavigation = 0;

  constructor(
    private auth: AuthenticationService
  )  

  ngOnInit() 
    const self = this;
    self.registerDOMEvents();
  

  registerDOMEvents() 
    const self = this;
    window.addEventListener('unload', () => 
      if (self.validNavigation === 0) 
        self.endSession();
      
    );
    document.addEventListener('keydown', (e) => 
      const key = e.which || e.keyCode;
      if (key === 116) 
        self.validNavigation = 1;
      
    );
  

  endSession() 
    const self = this;
    self.auth.clearStorage();
  

【讨论】:

点击浏览器的刷新按钮怎么样?【参考方案6】:

今天我遇到了同样的问题,并找到了一个可能的解决方案,我想与您分享。

在思考什么可以帮助区分刷新和关闭时,我想到了 cookie。我记得在没有明确过期日期的情况下设置 cookie,使其仅可用于当前会话。在浏览器关闭之前,当前会话显然是有效的。这不包括关闭选项卡,但我的问题是关于用户身份验证,我不想仅因为关闭选项卡而注销用户(我认为这与 ASP.NET 的ASPXAUTH cookie 相同)。

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

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

【讨论】:

【参考方案7】:
    $(window).bind('unload', function () 
        if (/Firefox[\/\s](\d+)/.test(navigator.userAgent) && new Number(RegExp.$1) >= 4) 
            console.log('firefox delete');
            var data =  async: false ;
            endSession(data);
            return null;
        
        else 
            console.log('NON-firefox delete');
            var data =  async: true ;
            endSession(data);
            return null;
        
    );

    function endSession(data) 
        var id = 0

        if (window)  // closeed
            id=1
        

        $.ajax(
            url: '/api/commonAPI/'+id+'?Action=ForceEndSession',
            type: "get",
            data: ,
            async: data.async,
            success: function () 
                console.log('Forced End Session');
            
        );
    

使用 if (window) 来确定是关闭还是重新加载。为我工作。

【讨论】:

在 Chrome 56 中,当用户关闭浏览器时,在 onunload 监听器中定义了窗口对象 ForceEndSession 是什么?【参考方案8】:

我刚试过这个,它解决了这个问题: 创建一个 sessionStorage 对象,当用户关闭浏览器时该对象将被销毁。我们可以通过查看 sessionStorage 对象来判断用户是否关闭了浏览器或刷新了页面(页面刷新时 sessionStorage 对象不会被销毁)。

【讨论】:

这个答案需要代码示例。在 Chrome 56 中 sessionStorage.getItem() 在用户关闭浏览器时在 onunload 监听器中正常工作。 即使在旧版本的 IE 上设置 localStorage 对象也对我有用【参考方案9】:

有办法。

我想在关闭选项卡或浏览器窗口时断开服务器上的用户,但不是在重新加载页面时(您可能希望区分重新加载/关闭事件以用于不同的目的,但您可能会从我的解决方案中受益) .基于 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
    
    

    在您的页面上,在body 上添加onload 到以下处理程序(伪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 的位置也不可靠,因为按钮不是在每个浏览器上都放置在相同的位置(例如左侧的关闭按钮)。

【讨论】:

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

使用 window.onbeforeunload 事件让案例离开页面,但它会包括刷新或锚标记....使用相同的验证标志,该过程的 1 个示例是 URL 检查(初始 URL = 当前 URL)或 F5 检查使用键码进行刷新,如果是锚标记,请使用 bind()

注意* 在 Chrome 的情况下,Keycode 可能会导致问题。

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<title>Test Page</title>

<style type='text/css'>
body 
    font-family: sans-serif;

</style>
<script src="jquery-1.9.1.js" type='text/javascript'></script>
<script type='text/javascript'>
var valid=false;
function wireUpEvents() 

if(valid)
alert("Page Refreshed or Redirected");
else

window.onbeforeunload = askWhetherToClose;


function askWhetherToClose(event) 

if(!valid)

    var msg;

    msg = "You're leaving the page, do you really want to?";
    event = event || window.event;
    event.returnValue = msg;
    return msg;

$(document).bind('keypress', function(e)  
 if (e.keyCode == 116) 

 // or you can insert some code to check page refresh
 valid = true; 

//wireUpEvents();
  
 ); 
 $("a").bind("click", function() 
//To check redirection using Anchor tags  
 valid = true; 
 //wireUpEvents();
 ); 
 
$(document).ready(function()  
 wireUpEvents(); 

 );
</script>
</head>
<body>
<p>Close the browser window, or navigate to <a href="http://***.com">***</a></p>
</body>
</html>

【讨论】:

当用户单击浏览器引用或返回按钮时,此代码不起作用.. 点击 X 时是否使用 FF 和 Chrome 进行测试?【参考方案11】:
<html>
<body onunload="doUnload()">
<script>
   function doUnload()
     if (window.event.clientX < 0 && window.event.clientY < 0)
       alert("Window closed");
     
     else
       alert("Window refreshed");
     
   
</script>
</body>
</html>

【讨论】:

【参考方案12】:

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

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

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

【讨论】:

【参考方案13】:

我之前的解决方案在 IE 中对我有用。 window.event 对于 IE 以外的浏览器将未定义,因为与其他浏览器不同,“事件”在 IE 中是全局定义的。如果是其他浏览器,您需要提供事件作为参数。另外,clientX 没有为 firefox 定义,我们应该使用 pageX。

试试这样的......应该适用于IE和firefox这个......

<html>
<body>
<script type="text/javascript">

window.onunload = function(e) 
// Firefox || IE
e = e || window.event;

var y = e.pageY || e.clientY;

if(y < 0)  alert("Window closed");
else alert("Window refreshed");


</script>
</body>
</html>

【讨论】:

感谢 Liv 1,我尝试了此代码,但它在 Firefox 中无法正常工作,在关闭选项卡并单击刷新按钮时会出现此问题。如果您有任何其他解决方案,请给我.. 此技术不能用于可靠地确定浏览器窗口是否已关闭。

以上是关于识别刷新和关闭浏览器操作的主要内容,如果未能解决你的问题,请参考以下文章

Javascript判断浏览器窗口(选项卡)的关闭与刷新

js 浏览器窗口 刷新关闭事件

刷新或关闭浏览器后数据消失 - Laravel

如何在 Angular 中处理浏览器选项卡关闭事件?只关闭不刷新

vue 关闭浏览器清缓存等的操作

关闭/刷新浏览器,刷新页面发送请求解决方案