检测浏览器或标签页的关闭

431
有没有跨浏览器的JavaScript/jQuery代码可以检测浏览器或浏览器标签页是否关闭,但不是由于点击链接导致的?

1
请查看我对这个问题的回答:https://dev59.com/6m865IYBdhLWcg3wl_s3#3735851 - Nivas
可以的!http://stackoverflow.com/questions/42706209/net-core-cookies-authentication-on-browser-close/42706331#42706331 - AP.
1
使用 sessionStorage 属性,它会在浏览器关闭时过期。https://www.w3schools.com/jsref/prop_win_sessionstorage.asp - csandreas1
检查这个答案!我发现它非常有用,覆盖了大多数情况。https://dev59.com/62Ei5IYBdhLWcg3w6PrZ#26275621 - Sukanya Pai
这个回答解决了你的问题吗?如何捕获浏览器窗口关闭事件? - Syed M. Sannan
我也尝试了很多方法,但最终 SignalR 帮助了我:https://dev59.com/D_UZpYgB1922wOYJspjl - Behnam Faghih
26个回答

353
如果我理解正确,您想知道何时有效地关闭一个选项卡/窗口。那么,在 JavaScript 中检测的唯一方法是使用 onunloadonbeforeunload 事件。
不幸的是(或者幸运?),这些事件在通过链接离开站点或单击浏览器的返回按钮时也会触发。所以这是我能给出的最好答案,我认为您不能本地检测到JavaScript中的纯 close。如果我理解有误,请纠正我。

50
没问题。您只能检测到页面卸载,而无法检测到窗口关闭。此外,onbeforeunload是非标准的,因此并不被所有浏览器支持。 - Guffa
11
我本来想使用“关闭时”功能,但注意到我的用户偶尔会按F5刷新屏幕。由于这种刷新会触发我的“关闭时”处理程序,这意味着我不能像我需要的那样使用它(即真正的“关闭标签页或窗口”)......该死,我们需要一个新的事件模型来处理所有这些! - Jeach
3
不再支持Chrome/Opera浏览器...https://www.chromestatus.com/feature/5349061406228480 - Samir Seetal
5
当然,这仍然有效,他们只是从“onbeforeunload”中移除了一个自定义的“String”返回值。所以现在你不能再卸载之前显示自定义消息了。 - jAndy
2
@jAndy @Guffa 我该如何找出哪个窗口触发了“unload”事件? - Egor Dudiak
显示剩余2条评论

171

来自MDN文档

由于某些原因,基于Webkit的浏览器不遵循对话框的规范。下面的示例几乎可以实现跨浏览器功能。

window.addEventListener("beforeunload", function (e) {
  var confirmationMessage = "\o/";

  (e || window.event).returnValue = confirmationMessage; //Gecko + IE
  return confirmationMessage;                            //Webkit, Safari, Chrome
});

这是一个处理所有浏览器的示例。


2
这是唯一一个对我的Chrome浏览器有效的解决方案。我没有尝试过其他任何方法。 - Chase Roberts
4
我尝试了许多解决方案,最终得出了这个最佳答案的组合,并在所有浏览器上进行了测试。 - mohamed-ibrahim
1
使用Firefox(>= ver. 44)仅打开一个选项卡时,此方法在关闭选项卡时无法完美运行。 - Raj
截至今天,使用所有最新版本的浏览器,对于Chrome、Firefox、Opera、IE11和Edge,在关闭选项卡、导航离开或关闭浏览器时,prompt都可以正常工作,并且在您打开多个选项卡时也可以正常工作,除了Chrome会在不提示的情况下关闭所有选项卡,至少在我的机器上是这样。 - Thierry
1
无法为 beforeunloadonbeforeunload 提供自定义消息。以下是2019年的浏览器兼容性:https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload#Browser_compatibility - Kenny Alvizuris
显示剩余4条评论

71
简单的解决方案
window.onbeforeunload = function () {
    return "Do you really want to close?";
};

11
这是什么巫术?(y) 它能在所有浏览器上运行吗?在 Chrome 上运行得很好。 - Ziv Weissman
11
刷新页面时会触发它,这是我的唯一问题。 - Leoncio
8
这个解决方案在Firefox和Chrome上不再可用。 - Mehdi Dehghani
2
这也会在页面离开事件上触发,而不仅仅是浏览器关闭或标签关闭。 - Sunil Acharya

23
<body onbeforeunload="ConfirmClose()" onunload="HandleOnClose()">

var myclose = false;

function ConfirmClose()
{
    if (event.clientY < 0)
    {
        event.returnValue = 'You have closed the browser. Do you want to logout from your application?';
        setTimeout('myclose=false',10);
        myclose=true;
    }
}

function HandleOnClose()
{
    if (myclose==true) 
    {
        //the url of your logout page which invalidate session on logout 
        location.replace('/contextpath/j_spring_security_logout') ;
    }   
}

//如果你在关闭仅有一个标签页的IE7浏览器或窗口,则此方法可行。


2
是的。但对于像IE8、Firefox这样的多标签浏览器,会有问题使用吗? - cometta
事实证明,在IE9中使用这段代码会导致当用户用鼠标点击后退、前进或刷新按钮时弹出此消息。 - Steve Wortham
提醒一下,我们在2007年就实现了类似的解决方案。大约一周前,这个解决方案在IE9中不再起作用。它在选项卡式浏览器中早已停止工作(或可能从未工作)。 - tjfo
我在Chromium/Ubuntu中使用控制台注入了window.onunload = "alert('wait')" window.onbeforeunload = "alert('wait... chrome!')",但是当我关闭选项卡时,两者都没有触发。 - icedwater
window.onunload = "alert('wait')" 和类似的代码实际上不起作用。根据MDN文章,应该为函数分配一个字符串值到事件对象的returnValue属性中,并返回相同的字符串。 - Dmytro Vyprichenko
@jyothis,这个在2022年还能用吗?看起来非常适合我想做的事情,但我还没有找到让它工作的方法。 - user16036297

21

对于类似任务,您可以使用sessionStorage在本地存储数据,直到关闭浏览器选项卡。

sessionStorage对象仅为一个会话存储数据(在关闭浏览器选项卡时数据将被删除)。(W3Schools)

这是我的笔记本

<div id="Notice">
    <span title="remove this until browser tab is closed"><u>dismiss</u>.</span>
</div>
<script>
    $("#Notice").click(function() {
     //set sessionStorage on click
        sessionStorage.setItem("dismissNotice", "Hello");
        $("#Notice").remove();
    });
    if (sessionStorage.getItem("dismissNotice"))
    //When sessionStorage is set Do stuff...
        $("#Notice").remove();
</script>

1
绝妙的想法。将其用于一个在线计时器,可以在多个页面上持续工作。到目前为止,我只知道localStorage。 - André R. Kohl
这对我来说是最好的答案,因为onbeforeunload事件即使在页面刷新时也会触发,而我并不希望如此。使用会话存储确实非常有帮助 :) - undefined

16
我需要在浏览器或选项卡关闭时自动注销用户,但当用户导航到其他链接时不需要注销。我也不希望出现确认提示。在与IE和Edge的斗争中,尤其是在经过一段时间后,这就是我最终采取的方法(在基于此答案的方法之后,已检查适用于IE 11、Edge、Chrome和Firefox)。
首先,在JS的beforeunload事件处理程序中,在服务器上启动倒计时计时器。对于IE和Edge,ajax调用需要同步才能正常工作。您还需要使用return;来防止出现确认对话框,如下所示:
    window.addEventListener("beforeunload", function (e) {        
      $.ajax({
          type: "POST",
          url: startTimerUrl,
          async: false           
      });
      return;
    });

启动计时器会将cancelLogout标志设置为false。如果用户刷新页面或导航到另一个内部链接,则服务器上的cancelLogout标志将设置为true。一旦计时器事件过期,它会检查cancelLogout标志以查看注销事件是否已被取消。如果计时器已被取消,则会停止计时器。如果浏览器或选项卡被关闭,则cancelLogout标志将保持false,事件处理程序将注销用户。
实现说明:我正在使用ASP.NET MVC 5,并在重写的Controller.OnActionExecuted()方法中取消注销。

这个很好用。你为什么要设置 "async: false" 呢?这会产生警告,因为同步 AJAX 调用已被弃用。谢谢! - cat_in_hat
1
@FoundWaldoException,如答案中所述,我发现在 IE 和 Edge 中需要将 async 设置为 false 才能使其工作。 - Ionian316
如何取消注销“OnActionExecuted”? - Kiquenet
@Kiquenet 只需停止在您代码中启动的计时器即可。 - Ionian316

13

我发现了一种方法,在我所有的浏览器上都可以运行

已在以下版本进行测试: Firefox 57、Internet Explorer 11、Edge 41、最新版本的 Chrome(它不会显示我的版本)

注意:当你以任何方式离开页面时(刷新、关闭浏览器、重定向、链接、提交..),onbeforeunload 都会触发。如果你只想在浏览器关闭时发生,请简单地绑定事件处理程序。

  $(document).ready(function(){         

        var validNavigation = false;

        // Attach the event keypress to exclude the F5 refresh (includes normal refresh)
        $(document).bind('keypress', function(e) {
            if (e.keyCode == 116){
                validNavigation = true;
            }
        });

        // Attach the event click for all links in the page
        $("a").bind("click", function() {
            validNavigation = true;
        });

        // Attach the event submit for all forms in the page
        $("form").bind("submit", function() {
          validNavigation = true;
        });

        // Attach the event click for all inputs in the page
        $("input[type=submit]").bind("click", function() {
          validNavigation = true;
        }); 

        window.onbeforeunload = function() {                
            if (!validNavigation) {     
                // ------->  code comes here
            }
        };

  });

如何为浏览器关闭添加单独的处理程序?我认为我们没有单独的事件可以用于此。 - blazehub
1
这非常有帮助。我需要调整A锚点,只针对实际的超链接触发。否则,点击Bootstrap选项卡会出现问题:$("a[href!='']").not('[href^="#"]').bind("click", function () - Ken Forslund

9

虽然没有事件,但是有一个属性window.closed,在本文撰写时被所有主流浏览器支持。因此,如果您真的需要知道,可以轮询窗口以检查该属性。

if(myWindow.closed){do things}

注意: 轮询任何内容通常不是最佳解决方案。如果可能,应使用window.onbeforeunload事件,唯一的注意事项是它也会在导航离开时触发。


9

抱歉,我无法在现有答案中添加评论,但是如果您想要实现一种警告对话框,我想提醒您任何事件处理程序函数都有一个参数 - event。在您的情况下,您可以调用event.preventDefault()来禁止自动离开页面,然后发出自己的对话框。我认为这比使用标准丑陋和不安全的alert()要好得多。我个人基于kendoWindow对象(Telerik的Kendo UI,除了kendoGrid和kendoEditor之外几乎完全开源)实现了自己的一套对话框。您也可以使用jQuery UI的对话框。请注意,这些东西是异步的,您需要绑定每个按钮的onclick事件处理程序,但这很容易实现。

然而,我确实同意缺乏真正的关闭事件是可怕的:例如,如果您想要在后端仅在真正关闭时重置会话状态,这是一个问题。


6
$(window).unload( function () { alert("Bye now!"); } );

10
这不适用于Firefox或Chrome浏览器。如果想要显示警报,请尝试使用beforeunload。像这样:$(window).on('beforeunload', function(){ alert ('Bye now')}); - AdrianoRR
7
根据 jQuery 文档的说法,大多数浏览器会忽略对 alert()、confirm() 和 prompt() 函数的调用。https://api.jquery.com/unload/ - katzmopolitan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接