Виявити закриття браузера або вкладки


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
Більше не працює над хромом / оперою ... 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 (> = ver. 44) з відкритою лише вкладкою.
Rajkishore

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

не даючи належного виходу, як визначено в питанні. Це також спрацьовувало на події залишення сторінки не лише закриття браузера або закриття вкладки
Sunil Acharya

48

Просте рішення

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

7
Що це за чаклунство? (y) чи працює це у всіх браузерах? чудово працює на хромі
Ziv Weissman

5
він запускається під час оновлення сторінки. це моя єдина проблема.
Лео Леонсіо

6
Це рішення більше не перебуває на Firefox та Chrome
Мехді Дехгані

Це також спрацьовувало на події залишення сторінки не лише закриття браузера або закриття вкладки
Sunil Acharya

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прапор на сервері встановлюється як вірно . Після закінчення події таймера він перевіряє cancelLogoutпрапор, щоб побачити, чи подія виходу була скасована. Якщо таймер скасовано, він зупинить таймер. Якщо веб-переглядач або вкладка були закриті, cancelLogoutпрапор залишився б помилковим, а обробник подій вимкне користувача.

Примітка про реалізацію: я використовую ASP.NET MVC 5 і скасовую вихід із Controller.OnActionExecuted()способом, що перекрито .


Це спрацювало чудово. Чи є причина, з якої ви робите "async: false"? Це генерує попередження про те, що синхронні виклики AJAX застаріли. Дякую!
cat_in_hat

1
@FoundWaldoException, як зазначено у відповіді, я виявив, що для роботи в IE та Edge для асинхронізації потрібно встановити значення false.
Іоніан316

Як скасовувати вихід OnActionExecuted?
Кікенет

@Kiquenet Просто зупиніть таймер, який був запущений у вашому коді.
Іоніан316

6

Вибачте, я не зміг додати коментар до однієї з існуючих відповідей, але у випадку, якщо ви хочете реалізувати своєрідний діалог попередження, я просто хотів зазначити, що будь-яка функція обробника подій має аргумент - подія. У вашому випадку ви можете зателефонувати event.preventDefault (), щоб заборонити автоматично залишати сторінку, а потім оформити власне діалогове вікно. Я вважаю це кращим варіантом, ніж використання стандартних негарних та небезпечних застережень (). Я особисто реалізував власний набір діалогових вікон на основі об’єкта kendoWindow (кері UI Telerik, який майже повністю відкритий, крім kendoGrid та kendoEditor). Ви також можете використовувати діалогові вікна з інтерфейсу jQuery. Зауважте, що такі речі є асинхронними, і вам потрібно буде прив’язати обробник до 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')});
Ось так

5
згідно з документами jQuery "Більшість браузерів ігнорують дзвінки на сповіщення (), підтвердження () та підказку ()" api.jquery.com/unload
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

3

Оскільки про це ще ніхто не згадував (8+ років пізніше): WebSocket може бути ще одним ефективним способом виявлення закритої вкладки. Поки вкладка відкрита і вказується на хост, клієнт може підтримувати активне з'єднання WebSocket з хостом.

Застереження: Зверніть увагу, що це рішення дійсно життєздатне лише для проекту, якщо WebSocket не потребує додаткових значних накладних витрат від того, що ви вже робите.

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

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


2
це гаразд. Але ви не можете поділитися будь-яким кодом або процедурою, щоб обробити його? Без цього для noob, як я, не можу зрозуміти
P

Власне, мені не було зрозуміло в першому коментарі. Я не знаю веб-сокет. Отже, я просто хотів подивитися, як впоратися
P

1
Посилання в моєму коментарі вище стосується деякого прикладу JS-коду WebSocket. Клієнтська частина JS - це легка частина. Цей код є моїм дуже конкретним випадком використання, хоча мені потрібно своєчасно припинити весь сервер додатків. Те, як ви пишете сервер WebSocket, залежить від вас і вимагає конфігурації на стороні сервера, щоб з'єднати все (багато людей віддають перевагу сервісу NodeJS w / Nginx frontend). Написання сервера з підтримкою 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, проте в хромі, однак ...
TrySpace

Будь-яке повернене значення (рядок) відображається лише в MSIE <= 11. Отже, в основному непридатне для всіх інших браузерів.
OSWorX

1

Перевірити це можна за допомогою window.closed в обробнику подій на подію "unload", як це, але потрібне використання тайм-ауту (тому результат не може бути гарантований, якщо smth затримує або запобігає закриттю вікна):

Приклад 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, у яких є кнопка «Закрити» для спливаючих вікон, і це викликає події «перед завантаженням». Крім того, селектор кнопок не працює належним чином, коли у вас на сітці є сітка 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?
Кікенет

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
Мохаммед

1
що таке sendkeylog?
Кікенет

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 ('розмір'), чи цього буде достатньо?
Бруно Анріке

Технічно, але він також видалить будь-які інші обробники, додані в іншому місці через 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.