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

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

【问题讨论】:

标签: javascript browser


【解决方案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 通信,我最终完成了以下流程:

          1. 在您的页面上,将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
            }
            
          2. 在您的页面上,在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)
                    }
                }
            } 
            
          3. 在服务器上,将断开连接请求收集到一个列表中,并设置一个计时器线程,它会定期检查列表(我每 20 秒使用一次)。一旦断开连接请求超时(即 5 秒过去),断开用户与服务器的连接。如果同时接收到断线请求取消,则将对应的断线请求从列表中删除,使用户不会被断线。

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

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

          这种方法仅限于支持 HTML5 本地存储的浏览器,因此您可能会为 MSIE7 等旧浏览器使用特定方法。

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

          【讨论】:

          • 我会使用sessionStorage 而不是localStorage,因为您只是在跟踪重新加载,因此没有理由让它持续存在。
          • 这是如何在现代浏览器中通过 HTML5 api 检测页面重新加载的答案。(对我有用):stackoverflow.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://stackoverflow.com">StackOverflow</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 中无法正常工作,在关闭选项卡并单击刷新按钮时会出现此问题。如果您有任何其他解决方案,请给我..
              • 此技术不能用于可靠地确定浏览器窗口是否已关闭。
              猜你喜欢
              • 1970-01-01
              • 2018-09-09
              • 2014-01-16
              • 2018-09-26
              • 1970-01-01
              • 1970-01-01
              • 2018-01-09
              • 1970-01-01
              相关资源
              最近更新 更多