如何捕获浏览器窗口关闭事件?

171

我想捕获浏览器窗口/选项卡关闭事件。 我已经使用jQuery尝试了以下方法:

jQuery(window).bind(
    "beforeunload", 
    function() { 
        return confirm("Do you really want to close?") 
    }
)

但是它也可以在表单提交时工作,这不是我想要的。我想要一个只在用户关闭窗口时触发的事件。


如果您想要非常精确,请查看此解决方案:https://dev59.com/D_UZpYgB1922wOYJspjl - Behnam Faghih
17个回答

231

beforeunload事件在用户因任何原因离开您的页面时触发。

例如,如果用户提交表单,点击链接,关闭窗口(或标签)或使用地址栏、搜索框或书签转到新页面,则会触发它。

您可以使用以下代码排除表单提交和超链接(除其他框架外):

var inFormOrLink;
$('a').on('click', function() { inFormOrLink = true; });
$('form').on('submit', function() { inFormOrLink = true; });

$(window).on("beforeunload", function() { 
    return inFormOrLink ? "Do you really want to close?" : null; 
})

对于 jQuery 版本早于 1.7 的情况,请尝试以下方法:

var inFormOrLink;
$('a').live('click', function() { inFormOrLink = true; });
$('form').bind('submit', function() { inFormOrLink = true; });

$(window).bind("beforeunload", function() { 
    return inFormOrLink ? "Do you really want to close?" : null; 
})
live 方法不能与 submit 事件一起使用,所以如果添加新的表单,您需要将处理程序绑定到它上面。请注意,如果不同的事件处理程序取消了提交或导航,则如果稍后实际关闭窗口,您将失去确认提示。您可以通过在submitclick事件中记录时间,并检查beforeunload是否晚于几秒钟来解决这个问题。

8
好的,工作得很好!较新版本的jQuery支持$('form').live('submit, function() { })。 - Venkat D.
6
您的解决方案很好,但如果进行刷新,我该如何取消事件?我希望只有在浏览器关闭的情况下才会触发事件,而不是在刷新的情况下。 - Refael
@SLaks的代码很好。如果用户点击“离开此页”弹出按钮,我想运行logout()函数。但是我如何检测用户是否已经点击了“离开此页”呢? - Bit_hunter
3
这个处理程序是否能够刷新页面,包括使用 Ctrl + rF5Ctrl + Shift + r 和改变浏览器的URL? - Arti
1
@Jonny:现在只需要使用.on() - SLaks
显示剩余8条评论

46

在表单的submit事件处理程序中,也许只需解绑beforeunload事件处理程序:

jQuery('form').submit(function() {
    jQuery(window).unbind("beforeunload");
    ...
});

3
不使用jQuery,只需在表单标签定义中指定如下内容即可实现相同效果吗?:<form onsubmit="window.onbeforeunload=null;"> - awe
4
但是你需要在每个表单中都包含 onsubmit=...。(我在某个 Web 应用程序中有许多表单) - KajMagnus

19
window.onbeforeunload = function () {
    return "Do you really want to close?";
};

17

如果需要跨浏览器解决方案(已在 Chrome 21、IE9、FF15 上测试),可以考虑使用以下代码,这是 Slaks 代码的稍微改进版本:

var inFormOrLink;
$('a').live('click', function() { inFormOrLink = true; });
$('form').bind('submit', function() { inFormOrLink = true; });

$(window).bind('beforeunload', function(eventObject) {
    var returnValue = undefined;
    if (! inFormOrLink) {
        returnValue = "Do you really want to close?";
    }
    eventObject.returnValue = returnValue;
    return returnValue;
}); 

请注意,自从Firefox 4以来,“您真的要关闭吗?”消息不再显示。 Firefox只显示一条通用消息。 有关详细信息,请参见https://developer.mozilla.org/en-US/docs/DOM/window.onbeforeunload中的说明。


4
这个在各种浏览器上都能够一致工作。只是简单说明一下,我将livebind语句都更新为on,这可以很好地与最新版本的jQuery配合使用。谢谢! - Sablefoste

10

我的回答旨在提供简单的基准。

如何操作

请参考@SLaks的答案

$(window).on("beforeunload", function() { 
    return inFormOrLink ? "Do you really want to close?" : null; 
})

浏览器最终关闭您的页面需要多长时间?

每当用户关闭页面(x按钮或CTRL+W),浏览器执行给定的beforeunload代码,但不是无限期地执行。唯一的例外是确认框(return 'Do you really want to close?)将等待用户响应。

Chrome: 2秒。
Firefox: ∞(或双击,或强制关闭)
Edge: ∞(或双击)
Explorer 11: 0秒。
Safari: TODO

我们用以下工具进行测试:

  • 一个 Node.js Express 服务器和请求日志记录
  • 以下简短的 HTML 文件

它会在浏览器关闭页面之前尽可能多地发送请求(同步执行)。

<html>
<body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
    <script>
    function request() {
        return $.ajax({
            type: "GET",
            url: "http://localhost:3030/" + Date.now(),
            async: true
        }).responseText;
    }
    window.onbeforeunload = () => {
        while (true) {
            request();
        }
        return null;
    }
    </script>
</body>
</html>

Chrome 输出:

GET /1480451321041 404 0.389 ms - 32  
GET /1480451321052 404 0.219 ms - 32  
...  
GET /hello/1480451322998 404 0.328 ms - 32

1957ms ≈ 2 seconds // we assume it's 2 seconds since requests can take few milliseconds to be sent.

4
考虑使用以下代码,它是对desm代码的稍作修改并具有更好的自我定位锚标签选择器,以便与第三方控件(如Telerik(例如:RadComboBox)和DevExpress)良好配合使用:
var inFormOrLink;
$('a[href]:not([target]), a[href][target=_self]').live('click', function() { inFormOrLink = true; });
$('form').bind('submit', function() { inFormOrLink = true; });

$(window).bind('beforeunload', function(eventObject) {
    var returnValue = undefined;
    if (! inFormOrLink) {
        returnValue = "Do you really want to close?";
    }
    eventObject.returnValue = returnValue;
    return returnValue;
});

1
这个答案是正确的,但是对于那些在刷新浏览器时遇到此事件发生问题的人,请将您的if更改为以下代码:if (inFormOrLink !== undefined && !inFormOrLink) - LeonPierre

3

我使用了Slaks的答案,但是它并没有正常工作。这是因为onbeforeunload returnValue被解析为字符串,然后显示在浏览器的确认框中。因此,值true被显示为"true"。

只需使用return就可以了。 下面是我的代码:

var preventUnloadPrompt;
var messageBeforeUnload = "my message here - Are you sure you want to leave this page?";
//var redirectAfterPrompt = "http://www.google.co.in";
$('a').live('click', function() { preventUnloadPrompt = true; });
$('form').live('submit', function() { preventUnloadPrompt = true; });
$(window).bind("beforeunload", function(e) { 
    var rval;
    if(preventUnloadPrompt) {
        return;
    } else {
        //location.replace(redirectAfterPrompt);
        return messageBeforeUnload;
    }
    return rval;
})

1
jQuery(window).bind("beforeunload", function (e) {
    var activeElementTagName = e.target.activeElement.tagName;
    if (activeElementTagName != "A" && activeElementTagName != "INPUT") {
        return "Do you really want to close?";
    }
})

1

不幸的是,无论是刷新、新页面重定向还是关闭浏览器,事件都会被触发。另一种选择是捕获触发事件的id,如果它是表单,则不触发任何函数,如果它不是表单的id,则在页面关闭时执行你想要执行的操作。我不确定这是否也可以直接实现,而且很繁琐。

在客户关闭选项卡之前,你可以做一些小事情。javascript检测浏览器关闭选项卡/关闭浏览器,但如果你的操作列表很长,选项卡在操作完成之前关闭,那么你就无能为力了。你可以尝试一下,但根据我的经验,不要依赖它。

window.addEventListener("beforeunload", function (e) {
  var confirmationMessage = "\o/";
  /* Do you small action code here */
  (e || window.event).returnValue = confirmationMessage; //Gecko + IE
  return confirmationMessage;                            //Webkit, Safari, Chrome
});

https://developer.mozilla.org/en-US/docs/Web/Reference/Events/beforeunload?redirectlocale=en-US&redirectslug=DOM/Mozilla_event_reference/beforeunload


1
也许你可以处理 OnSubmit 事件,并设置一个标志,在你的 OnBeforeUnload 处理程序中稍后进行检查。

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