Определить браузер или закрытие вкладки


306

Существует ли какой-либо кросс-браузерный код JavaScript / jQuery, чтобы определить, закрывается ли браузер или вкладка браузера, но не из-за нажатия на ссылку?


1
Смотрите мой ответ на этот вопрос: stackoverflow.com/questions/3735198/…
Nivas


Используйте sessionStorage свойство, оно истечет после закрытия браузера. w3schools.com/jsref/prop_win_sessionstorage.asp
csandreas1

Проверьте этот ответ! Я нашел это чрезвычайно полезным и покрывает большинство случаев. stackoverflow.com/a/26275621/7192927
SukanyaPai

Ответы:


273

Если я вас правильно понял, вы хотите знать, когда вкладка / окно эффективно закрывается. Ну, AFAIK - единственный способ Javascriptобнаружить такие вещи onunloadи onbeforeunloadсобытия.

К сожалению (или к счастью?), Эти события также запускаются, когда вы покидаете сайт над linkкнопкой браузера или назад. Так что это лучший ответ, который я могу дать, я не думаю, что вы можете непосредственно определить чистоту closeв Javascript. Поправь меня, если я здесь не прав.


39
Верный. Вы можете определить только когда страница выгружена, а не когда окно закрыто. Кроме того, onbeforeunload не является стандартным, поэтому поддерживается не всеми браузерами.
Гуффа

7
Я также хотел использовать функцию «при закрытии», но заметил, что мои пользователи иногда обновляют экран нажатием клавиши F5. Так как мои обработчики «при закрытии» вызываются при таком обновлении, это означает, что я не могу использовать его так, как мне было нужно (что было настоящей «закрытой вкладкой или окном») ... черт возьми, нам нужна новая модель событий за все это!
Jeach

1
Больше не работает над Chrome / Opera ... Chromestatus.com/feature/5349061406228480
Самир Ситал

2
Конечно, это все еще будет работать, они просто удалили пользовательское Stringвозвращаемое значение из onbeforeunload. Так что теперь вы больше не сможете отображать пользовательское сообщение перед выгрузкой.
jAndy

@jAndy @Guffa Как узнать, какое окно открылось unload?
Егор Дудяк

125

Из документации Firefox

По некоторым причинам браузеры на основе Webkit не следуют спецификации для диалогового окна. Практически перекрестный пример будет близок к приведенному ниже.

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

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

Этот пример для обработки всех браузеров.


2
Это единственное решение, которое работает для моего браузера Chrome. Я не пробовал других.
Чейз Робертс

4
да, я пробую много решений, и в конце я приду с этим, комбинация для лучших ответов, и я проверяю это на всех браузерах.
Мохамед-Ибрагим

1
Этот метод не работает идеально при закрытии вкладки при использовании firefox (> = версия 44) с открытой только вкладкой.
Раджкишор

На сегодняшний день, при использовании всех последних версий браузеров, приглашение работает при закрытии вкладки, переходе из режима ожидания или закрытии браузера для Chrome, Firefox, Opera, IE11 и Edge, а также при наличии нескольких открытых вкладок, за исключением Chrome, где Chrome закрывает все вкладки. без подсказок, ну на моей машине хотя бы.
Тьерри

не выдает должное, как определено в вопросе. Это также вызвало событие закрытия страницы, а не только закрытие браузера или закрытие вкладки
Сунил Ачарья

48

Простое решение

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

7
Что это за колдовство? (у) это работает во всех браузерах? отлично работает на Chrome
Зив Вайсман

5
он срабатывает при обновлении страницы. это моя единственная проблема.
Лев Леонсио

6
Это решение больше не работает в Firefox и Chrome
Mehdi Dehghani

Это также вызвало событие закрытия страницы, а не только закрытие браузера или закрытие вкладки
Сунил Ачарья

20
<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. есть проблема с этим?
комета

Оказывается, использование этого кода в IE9 вызовет всплывающее сообщение, когда пользователь щелкает мышью кнопки «назад», «вперед» или «обновить».
Стив Уортам,

Просто напомнить, что мы внедрили подобное решение еще в 2007 году. Это решение больше не работает в IE9 примерно неделю назад. Он давно перестал работать (или, возможно, никогда не работал) в браузерах с вкладками.
tjfo

Я сделал инъекцию window.onunload = "alert('wait')"и window.onbeforeunload = "alert('wait... chrome!')"использовал консоль в Chromium / Ubuntu, но ни один не запустился, когда закрыл вкладку.
ледяная вода

window.onunload = "alert('wait')"и такое не должно работать на самом деле. «Функция должна присвоить строковое значение свойству returnValue объекта Event и вернуть ту же строку». Пожалуйста, взгляните на статью MDN
Дмитрий Выприченко

8

Мне нужно было автоматически выходить из системы при закрытии браузера или вкладки, но не при переходе пользователя к другим ссылкам. Я также не хотел, чтобы в этом случае отображался запрос на подтверждение. После того, как я некоторое время боролся с этим, особенно с IE и Edge, вот что я закончил (проверил работу с IE 11, Edge, Chrome и Firefox) после обоснования подхода этим ответом .

Сначала запустите таймер обратного отсчета на сервере в beforeunloadобработчике событий в JS. Для правильной работы IE и Edge вызовы ajax должны быть синхронными. Вы также должны использовать, return;чтобы не показывать диалоговое окно подтверждения так:

    window.addEventListener("beforeunload", function (e) {        
      $.ajax({
          type: "POST",
          url: startTimerUrl,
          async: false           
      });
      return;
    });

Запуск таймера устанавливает cancelLogoutфлаг в false . Если пользователь обновляет страницу или переходит на другую внутреннюю ссылку, cancelLogoutфлаг на сервере устанавливается в значение true . По истечении события таймера он проверяет cancelLogoutфлаг, чтобы увидеть, было ли отменено событие выхода из системы. Если таймер был отменен, он остановит таймер. Если бы браузер или вкладка были закрыты, то cancelLogoutфлаг оставался бы ложным, а обработчик события выводил бы пользователя из системы.

Замечание по реализации: я использую ASP.NET MVC 5 и отменяю выход из системы переопределенным Controller.OnActionExecuted()методом.


Это сработало отлично. Есть ли причина, по которой вы делаете «async: false»? Это генерирует предупреждения о том, что синхронные вызовы AJAX устарели. Спасибо!
cat_in_hat

1
@FoundWaldoException, как отмечалось в ответе, я обнаружил, что для асинхронности необходимо установить значение false, чтобы это работало в IE и Edge.
Ionian316

Как отменить выход OnActionExecuted?
Kiquenet

@Kiquenet Просто остановите таймер, который был запущен в вашем коде.
Ionian316

6

Извините, я не смог добавить комментарий к одному из существующих ответов, но в случае, если вы хотите реализовать своего рода диалоговое окно с предупреждением, я просто хотел упомянуть, что любая функция-обработчик события имеет аргумент - событие. В вашем случае вы можете вызвать event.preventDefault (), чтобы запретить покидать страницу автоматически, а затем запустить собственный диалог. Я считаю, что это лучший вариант, чем использование стандартных уродливых и небезопасных оповещений (). Я лично реализовал свой собственный набор диалоговых окон на основе объекта kendoWindow (пользовательский интерфейс Telerik Kendo, который почти полностью открыт, за исключением kendoGrid и kendoEditor). Вы также можете использовать диалоговые окна из jQuery UI. Обратите внимание, что такие вещи асинхронны, и вам нужно будет привязать обработчик к событию onclick каждой кнопки, но это все довольно просто реализовать.

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


6

Для подобных задач вы можете использовать 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>

5

Событие отсутствует, но есть свойство, window.closedкоторое поддерживается во всех основных браузерах на момент написания этой статьи. Таким образом, если вам действительно нужно знать, вы можете опрашивать окно, чтобы проверить это свойство.

if(myWindow.closed){do things}

Примечание. Как правило, опрос не является лучшим решением. window.onbeforeunloadСобытие должно быть использовано , если это возможно, единственный нюанс в том , что она также срабатывает , если вы уйдете.


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

9
Это не будет работать на Firefox или Chrome. Попробуйте, beforeunloadесли хотите отобразить предупреждение. Как это:$(window).on('beforeunload', function(){ alert ('Bye now')});
AdrianoRR

5
согласно документам jQuery «Большинство браузеров игнорируют вызовы alert (), verify
katzmopolitan

4

Попробуйте использовать это:

window.onbeforeunload = function (event) {
    var message = 'Important: Please click on \'Save\' button to leave this page.';
    if (typeof event == 'undefined') {
        event = window.event;
    }
    if (event) {
        event.returnValue = message;
    }
    return message;
};

$(function () {
    $("a").not('#lnkLogOut').click(function () {
        window.onbeforeunload = null;
    });
    $(".btn").click(function () {
        window.onbeforeunload = null;
});
});

3

Я нашел способ, который работает во всех моих браузерах .

Протестировано на следующих версиях: 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

Это было очень полезно. Мне нужно было настроить якорь A так, чтобы он срабатывал только для реальных гиперссылок. В противном случае нажатие на вкладки начальной загрузки может привести к путанице: $ ("a [href! = '']"). Not ('[href ^ = "#"]'). Bind ("click", function ()
Ken Forslund

3

Поскольку никто еще не упомянул об этом (8+ лет спустя): WebSocket может стать еще одним эффективным способом обнаружения закрытой вкладки. Пока вкладка открыта и направлена ​​на хост, клиент может поддерживать активное соединение WebSocket с хостом.

Предостережение: обратите внимание, что это решение действительно жизнеспособно для проекта, только если WebSocket не требует каких-либо дополнительных значительных накладных расходов от того, что вы уже делаете.

В течение разумного периода времени (например, 2 минуты) серверная сторона может определить, что клиент отключился после отключения WebSocket, и выполнить любое действие, например, удаление загруженных временных файлов. (В моем крайне специализированном сценарии использования моя цель состояла в том, чтобы завершить работу сервера приложений localhost через три секунды после разрыва соединения WebSocket и прекращения всех действий CGI / FastCGI - любые другие поддерживающие соединение не влияют на меня.)

У меня были проблемы с получением обработчика события onunload для правильной работы с маяками (как рекомендовано в этом ответе ). Закрытие вкладки не вызывало срабатывания маяка, а открытые вкладки вызывали его таким образом, что это могло вызвать проблемы. WebSocket решил проблему, с которой я столкнулся, более аккуратно, потому что соединение закрывается примерно в то же самое время, когда вкладка закрывается, а переключение страниц в приложении просто открывает новое соединение WebSocket внутри окна задержки.


2
это нормально. Но вы не можете поделиться каким-либо кодом или процедурой, чтобы справиться с этим? Без этого для такого нуба как я не могу понять
P Satish Patro

На самом деле, я не был ясен в своем первом комментарии. Я не знаю, веб-сокет. Итак, я просто хотел посмотреть, как справиться
P Satish Patro

1
Ссылка в моем комментарии выше ведет к некоторому примеру кода JS WebSocket. JS-часть клиента является легкой частью. Этот код предназначен для моего очень конкретного случая использования, хотя мне нужно своевременно завершить работу всего сервера приложений. То, как вы пишете сервер WebSocket, зависит от вас и требует конфигурации на стороне сервера для подключения всего (многие люди предпочитают серверную часть NodeJS с внешним интерфейсом Nginx). Написание сервера с поддержкой TCP / IP - сложная тема, не подходящая для обсуждения в комментариях, и ее слишком сложно настроить только для обнаружения этой конкретной проблемы.
CubicleSoft

2
//Detect Browser or Tab Close Events
$(window).on('beforeunload',function(e) {
  e = e || window.event;
  var localStorageTime = localStorage.getItem('storagetime')
  if(localStorageTime!=null && localStorageTime!=undefined){
    var currentTime = new Date().getTime(),
        timeDifference = currentTime - localStorageTime;

    if(timeDifference<25){//Browser Closed
       localStorage.removeItem('storagetime');
    }else{//Browser Tab Closed
       localStorage.setItem('storagetime',new Date().getTime());
    }

  }else{
    localStorage.setItem('storagetime',new Date().getTime());
  }
});

JSFiddle Link

Привет всем, я смог добиться кликов «Определить событие закрытия браузера и вкладки», используя локальное хранилище браузера и метку времени. Надеюсь, что все вы решите свои проблемы с помощью этого решения.

После моего первоначального исследования я обнаружил, что когда мы закрываем браузер, браузер закрывает все вкладки одну за другой, чтобы полностью закрыть браузер. Следовательно, я заметил, что между закрытием вкладок будет очень небольшая задержка. Поэтому я принял эту задержку за основную точку проверки и смог обнаружить событие закрытия браузера и вкладки.

Я протестировал его в браузере Chrome версии 76.0.3809.132 и обнаружил, что работает

:) Проголосуйте, если вы нашли мой ответ полезным ....


Ну, это дало мне идею. Я устанавливаю метку времени плюс 10 секунд в локальном хранилище после входа в систему и события до загрузки. При загрузке я проверяю, прошло ли время, затем перенаправляю на страницу входа. Спасибо :)
G4BB3R

1
window.onbeforeunload = function() {
  console.log('event');
  return false; //here also can be string, that will be shown to the user
}

2
here also can be string, that will be shown to the userв Firefox это не так, как в Chrome, однако ...
TrySpace

Любое возвращаемое значение (строка) отображается только в MSIE <= 11. Так что в принципе бесполезно для всех других браузеров.
OSWorX

1

Проверить это можно с помощью window.closed в обработчике события для события 'unload', подобного этому, но использование тайм-аута необходимо (поэтому результат не может быть гарантирован, если что-то задерживается или препятствует закрытию окна):

Пример JSFiddle (протестировано на поздних версиях Safari, FF, Chrome, Edge и IE11)

var win = window.open('', '', 'width=200,height=50,left=200,top=50');
win.document.write(`<html>
   <head><title>CHILD WINDOW/TAB</title></head>
   <body><h2>CHILD WINDOW/TAB</h2></body>
</html>`);
win.addEventListener('load',() => {
    document.querySelector('.status').innerHTML += '<p>Child was loaded!</p>';
});
win.addEventListener('unload',() => {
    document.querySelector('.status').innerHTML += '<p>Child was unloaded!</p>';
    setTimeout(()=>{
        document.querySelector('.status').innerHTML +=  getChildWindowStatus();
    },1000);
});
win.document.close()
document.querySelector('.check-child-window').onclick = ()=> {
    alert(getChildWindowStatus());
}
function getChildWindowStatus() {
  if (win.closed) { 
      return 'Child window has been closed!';
  } else {
      return 'Child window has not been closed!';
  }
}

1

Я перепробовал все вышеперечисленные решения, но ни одно из них не сработало для меня, особенно потому, что в моем проекте есть некоторые компоненты Telerik, у которых есть кнопка «Закрыть» для всплывающих окон, и она вызывает событие «beforeunload». Кроме того, кнопка выбора не работает должным образом, когда на вашей странице есть сетка Telerik (я имею в виду кнопки внутри сетки). Поэтому я не смог использовать ни одно из предложенных выше предложений. Наконец-то это решение сработало для меня. Я добавил событие onUnload в тег body _Layout.cshtml. Что-то вроде этого:

<body onUnload="LogOff()">

а затем добавьте функцию LogOff для перенаправления в Account / LogOff, который является встроенным методом в Asp.Net MVC. Теперь, когда я закрываю браузер или вкладку, он перенаправляется на метод LogOff, и пользователь должен войти в систему, когда вернется. Я проверил это в Chrome и Firefox. И это работает!

  function LogOff() {
        $.ajax({
            url: "/Account/LogOff",
            success: function (result) {

                                        }
               });
       }

0
window.onbeforeunload = function ()
{       

    if (isProcess > 0) 
    {
        return true;       
    }   

    else
    { 
        //do something      
    }
}; 

Эта функция отображает диалоговое окно подтверждения, если вы закрываете окно или обновляете страницу во время какого-либо процесса в браузере. Эта функция работает во всех браузерах. Вы должны установить isProcess var в вашем процессе ajax.


полный образец для набора isProcess?
Kiquenet

0
window.addEventListener("beforeunload", function (e) {
 var confirmationMessage = "tab close";

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

На самом деле я хотел показать подтверждающее сообщение, если пользователь закрыл вкладку ТОЛЬКО. Это работает для меня. Но я сталкиваюсь с проблемой, что, если я нажимаю на любую ссылку на той же странице, то также отображается сообщение с подтверждением. Для получения дополнительной информации см. W3schools.com/code/tryit.asp?filename=FEK2KWUN9R8Z @Tunaki
Mohammed

1
что такое sendkeylog?
Kiquenet

0

Как уже упоминалось @jAndy, не существует должного кода javascript для обнаружения закрытия окна. Я начал с того, что предложил @Syno.

Я прошел через такую ​​ситуацию и при условии, что вы выполните эти шаги, вы сможете обнаружить это.
Я тестировал его на Chrome 67+ и Firefox 61+.

var wrapper = function () { //ignore this

var closing_window = false;
$(window).on('focus', function () {
    closing_window = false; 
   //if the user interacts with the window, then the window is not being 
   //closed
});

$(window).on('blur', function () {

    closing_window = true;
    if (!document.hidden) { //when the window is being minimized
        closing_window = false;
    }
    $(window).on('resize', function (e) { //when the window is being maximized
        closing_window = false;
    });
    $(window).off('resize'); //avoid multiple listening
});

$('html').on('mouseleave', function () {
    closing_window = true; 
    //if the user is leaving html, we have more reasons to believe that he's 
    //leaving or thinking about closing the window
});

$('html').on('mouseenter', function () {
    closing_window = false; 
    //if the user's mouse its on the page, it means you don't need to logout 
    //them, didn't it?
});

$(document).on('keydown', function (e) {

    if (e.keyCode == 91 || e.keyCode == 18) {
        closing_window = false; //shortcuts for ALT+TAB and Window key
    }

    if (e.keyCode == 116 || (e.ctrlKey && e.keyCode == 82)) {
        closing_window = false; //shortcuts for F5 and CTRL+F5 and CTRL+R
    }
});

// Prevent logout when clicking in a hiperlink
$(document).on("click", "a", function () {
    closing_window = false;
});

// Prevent logout when clicking in a button (if these buttons rediret to some page)
$(document).on("click", "button", function () {
    closing_window = false;

});
// Prevent logout when submiting
$(document).on("submit", "form", function () {
    closing_window = false;
});
// Prevent logout when submiting
$(document).on("click", "input[type=submit]", function () {
    closing_window = false;
});

var toDoWhenClosing = function() {

    //write a code here likes a user logout, example: 
    //$.ajax({
    //    url: '/MyController/MyLogOutAction',
    //    async: false,
    //    data: {

    //    },
    //    error: function () {
    //    },
    //    success: function (data) {
    //    },
    //});
};


window.onbeforeunload = function () {
    if (closing_window) {
        toDoWhenClosing();
    }
};

};


1
У вас есть некоторые проблемы в вашем коде JavaScript. Первое, что я заметил, это то, что вы будете постоянно связываться с resizeразмытым окном. Если он будет размыт в 100 раз, у вас будет 100 слушателей, что в конечном итоге приведет к замедлению работы браузера.
Кайл

Я положил $ (window) .off ('resize'), этого будет достаточно?
Бруно Энрике

Технически, но он также удалит все другие обработчики, которые были добавлены в другом месте через jQuery.
Кайл

-2

попробуйте это, я уверен, что это будет работать для вас.

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type='text/javascript'>
    $(function() {

        try{
            opera.setOverrideHistoryNavigationMode('compatible');
            history.navigationMode = 'compatible';
        }catch(e){}

        function ReturnMessage()
        {
            return "wait";
        }

        function UnBindWindow()
        {
            $(window).unbind('beforeunload', ReturnMessage);
        }

        $(window).bind('beforeunload',ReturnMessage );
    });
</script>

-3

Попробуй это. Это сработает. Метод выгрузки jquery устарел.

window.onbeforeunload = function(event) {
    event.returnValue = "Write something clever here..";
};
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.