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

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

27 ответов

Решение

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

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

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

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

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

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

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

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

window.onbeforeunload = function () {
    return "Do you really want to close?";
};
<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, если вы закрываете вкладку или браузер только с одной вкладкой

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

Мне нужно было автоматически выходить из системы при закрытии браузера или вкладки, но не при переходе пользователя к другим ссылкам. Я также не хотел, чтобы в этом случае отображался запрос на подтверждение. После того, как я некоторое время боролся с этим, особенно с 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 флаг ложно. Если пользователь обновляет страницу или переходит на другую внутреннюю ссылку, cancelLogout флаг на сервере установлен в true. Как только событие таймера истекает, оно проверяет cancelLogout флаг, чтобы увидеть, было ли отменено событие выхода из системы. Если таймер был отменен, то он остановит таймер. Если браузер или вкладка были закрыты, то cancelLogout флаг останется ложным, а обработчик события выйдет из системы.

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

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

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

  });

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

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

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

if(myWindow.closed){do things}

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

onunload - вот ответ. Кроссбраузер тоже.

window.onunload = function(){alert("The window is closing now!");}

onunload выполняется только при закрытии страницы:

Эти события запускаются, когда окно выгружает свое содержимое и ресурсы.

Я тестировал его на хроме, он не запускается даже при обновлении страницы и при переходе на другую страницу.

Предупреждение может не отображаться из-за того, как javascript выполняет код... но он определенно попадет в код.

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

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

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

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

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

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

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;
});
});

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

Google Chrome не будет взаимодействовать, если пользователь не взаимодействует с веб-страницей, это связано с вредоносными веб-сайтами..... В этом случае, если вы не нажмете на текстовую область, всплывающее окно не появится.

      <!DOCTYPE html>
<html>
<head>
</head>
<body>
    <form>
        <textarea placeholder = "Write...."></textarea>
    </form>
    <script type="text/javascript">
        window.addEventListener('beforeunload', function (e) {
            e.returnValue = '';
        });
    </script>
</body>
</html>

В браузер были внесены обновления, чтобы лучше отслеживать пользователя при выходе из приложения. Событие «visibilitychange» позволяет отслеживать, когда страница скрыта от другой вкладки или закрыта. Вы можете отслеживать состояние видимости документа. Свойство document.visibilityState вернет текущее состояние. Вам нужно будет отслеживать вход и выход, но это ближе к цели.

Это поддерживается более новыми браузерами, но сафари (как мы знаем) никогда не соответствует стандартам. Вы можете использовать «pageshow» и «pagehide» для работы в сафари.

Вы даже можете использовать новые API, такие как sendBeacon, для отправки одностороннего запроса на сервер, когда вкладка закрыта и не следует ожидать ответа.

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

      export class UserLoginStatus
{
    /**
     * This will add the events and sign the user in.
     */
    constructor()
    {
        this.addEvents();
        this.signIn();
    }

    /**
     * This will check if the browser is safari. 
     * 
     * @returns {bool}
     */
    isSafari()
    {
        if(navigator && /Safari/.test(navigator.userAgent) && /Chrome/.test(navigator.userAgent))
        {
            return (/Google Inc/.test(navigator.vendor) === false);
        }
        return false;
    }

    /**
     * This will setup the events array by browser.
     * 
     * @returns {array}
     */
    setupEvents()
    {
        let events = [
            ['visibilitychange', document, () =>
            {
                if (document.visibilityState === 'visible')
                {
                    this.signIn();
                    return;
                }

                this.signOut();
            }]
        ];

        // we need to setup events for safari
        if(this.isSafari())
        {
            events.push(['pageshow', window, (e) =>
            {
                if(e.persisted === false)
                {
                    this.signIn();
                }
            }]);

            events.push(['pagehide', window, (e) =>
            {
                if(e.persisted === false)
                {
                    this.signOut();
                }
            }]);
        }

        return events;
    }

    /**
     * This will add the events.
     */
    addEvents()
    {
        let events = this.setupEvents();
        if(!events || events.length < 1)
        {
            return;
        }

        for(var i = 0, length = events.length; i < length; i++)
        {
            var event = events[i];
            if(!event)
            {
                continue;
            }

            event[1].addEventListener(event[0], event[3]);
        }
    }

    /**
     * 
     * @param {string} url 
     * @param {string} params 
     */
    async fetch(url, params)
    {
        await fetch(url, 
        {
            method: 'POST',
            body: JSON.stringify(params)
        });
    }

    /**
     * This will sign in the user.
     */
    signIn()
    {
        // user is the app
        const url = '/auth/login';
        let params = 'userId=' + data.userId;

        this.fetch(url, params);
    }

    /**
     * This will sign out the user.
     */
    signOut()
    {
        // user is leaving the app

        const url = '/auth/logout';
        let params = 'userId=' + data.userId;

        if(!('sendBeacon' in window.navigator))
        {
            // normal ajax request here
            this.fetch(url, params);
            return;
        }

        // use a beacon for a more modern request the does not return a response
        navigator.sendBeacon(url, new URLSearchParams(params));
    }
}
window.onbeforeunload = function() {
  console.log('event');
  return false; //here also can be string, that will be shown to the user
}
//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

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

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

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

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

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

<body onUnload="LogOff()">

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

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

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

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

Со страницы MDN :

Избегайте выгрузки и перед выгрузкой

Раньше многие веб-сайты использовалиилисобытия для отправки аналитики в конце сеанса. Однако это крайне ненадежно. Во многих ситуациях, особенно на мобильных устройствах, браузер не запускает unload, beforeunload, или pagehideсобытия. Например, эти события не будут срабатывать в следующей ситуации:

  1. Пользователь загружает страницу и взаимодействует с ней.
  2. По завершении они переключаются на другое приложение вместо того, чтобы закрывать вкладку.
  3. Позже они закрывают приложение браузера с помощью диспетчера приложений телефона.

Самый надежный способ сделать это — отправить данные пособытие.

ОтvisibilitychangeПримечания по использованию :

Это событие срабатывает сvisibilityStateкогда пользователь переходит на новую страницу, переключает вкладки, закрывает вкладку, сворачивает или закрывает браузер или, на мобильном устройстве, переключается из браузера в другое приложение. Переход кhidden— это последнее событие, которое надежно отслеживается страницей, поэтому разработчикам следует рассматривать его как вероятное завершение сеанса пользователя (например, для ).

На также упоминается, что мы можем использоватьfetch()сдля параметра установлено значение true для отправки аналитических данных.

Эту опцию можно использовать, чтобы позволить запросу пережить страницу. Получить с помощьюkeepaliveфлаг является заменойотправки аналитических данныхNavigator.sendBeacon()первой странице MDNAPI.

window.onbeforeunload = function ()
{       

    if (isProcess > 0) 
    {
        return true;       
    }   

    else
    { 
        //do something      
    }
}; 

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

Проверить это можно с помощью 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. Прослушивайте изменения в URL- адресе с помощью onpopstate и установите для переменной sessionStorage значение 1
  2. Прослушайте загрузку страницы и установите для этой переменной sessionStorage значение 0
  3. На beforeunload , проверьте , если переменная равна 0. Если это так то это означает , что пользователь закрывает и не меняя URL.

Это все еще окольный путь, но для меня он имеет смысл

Как уже упоминалось @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();
    }
};

};

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

window.onbeforeunload = function(event) {
    event.returnValue = "Write something clever here..";
};

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

<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>
<script type="text/javascript" language="Javascript">

function DetectBrowserExit()
{
   alert('Execute task which do you want before exit');
}

window.onbeforeunload = function(){ DetectBrowserExit(); }

</script>

Я тестировал этот сценарий в следующих веб-браузерах: В настоящий момент веб-браузер Opera не поддерживает событие onBeforeUnload. Internet Explorer Mozilla Firefox Google Chrome Safari

Другие вопросы по тегам