Как захватить событие закрытия окна браузера? - PullRequest
139 голосов
/ 27 октября 2009

Я хочу захватить событие закрытия окна / вкладки браузера. Я пробовал следующее с jQuery:

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

Но это работает и при отправке формы, а это не то, что я хочу. Мне нужно событие, которое срабатывает только тогда, когда пользователь закрывает окно.

Ответы [ 17 ]

196 голосов
/ 27 октября 2009

Событие 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, поэтому, если вы добавляете новую форму, вам необходимо также привязать к ней обработчик.

Обратите внимание, что если другой обработчик событий отменяет отправку или навигацию, вы потеряете запрос на подтверждение, если позднее окно действительно закроется. Это можно исправить, записав время в событиях submit и click и проверив, произойдет ли beforeunload больше, чем через пару секунд.

44 голосов
/ 27 октября 2009

Может быть, просто отсоединить обработчик событий beforeunload в обработчике событий формы submit:

jQuery('form').submit(function() {
    jQuery(window).unbind("beforeunload");
    ...
});
15 голосов
/ 25 сентября 2012

Для кросс-браузерного решения (протестировано в 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 появляется сообщение "Вы действительно хотите закрыть?" не отображается FF просто отображает общее сообщение. См примечание в https://developer.mozilla.org/en-US/docs/DOM/window.onbeforeunload

10 голосов
/ 09 марта 2014
window.onbeforeunload = function () {
    return "Do you really want to close?";
};
4 голосов
/ 30 ноября 2016

Мой ответ нацелен на обеспечение простых ориентиров.

КАК

См. @ 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 : ∞ (или двойной щелчок, или принудительное закрытие)
Край : ∞ (или двойной щелчок)
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>

Хромированный выход:

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 голосов
/ 14 мая 2013

Для решения, которое хорошо работает со сторонними элементами управления, такими как Telerik (например, RadComboBox) и DevExpress, которые используют теги Anchor по разным причинам, рассмотрите возможность использования следующего кода, который является слегка подправленной версией кода desm с лучшей селектор для меток привязки самоназначения:

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;
});
3 голосов
/ 30 апреля 2012

Я использовал ответ Slaks, но это не сработало как есть, поскольку onbeforeunload returnValue анализируется как строка и затем отображается в окне подтверждения браузера. Таким образом, значение true отображалось, как «true».

Просто с помощью возврата сработало. Вот мой код

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 голос
/ 27 октября 2009

Возможно, вы могли бы обработать OnSubmit и установить флаг, который вы позже отметите в обработчике OnBeforeUnload.

1 голос
/ 10 декабря 2015

К сожалению, будет ли инициировано событие перезагрузки, перенаправления новой страницы или закрытия браузера. Альтернативой является перехват идентификатора, инициирующего событие, и если это форма, не запускайте никакую функцию, а если это не идентификатор формы, делайте то, что хотите, когда страница закрывается. Я не уверен, что это также возможно напрямую и утомительно.

Вы можете сделать небольшие вещи, прежде чем клиент закроет вкладку. 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 голос
/ 30 июня 2015
jQuery(window).bind(
                    "beforeunload",
                      function (e) {
                          var activeElementTagName = e.target.activeElement.tagName;
                          if (activeElementTagName != "A" && activeElementTagName != "INPUT") {
                              return "Do you really want to close?";
                          }
                      })
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...