Jak uchwycić zdarzenie zamknięcia okna przeglądarki?

149

Chcę uchwycić zdarzenie zamknięcia okna / karty przeglądarki. W jQuery próbowałem następujących rzeczy:

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

Ale działa również przy przesyłaniu formularzy, czego nie chcę. Chcę, aby zdarzenie było wyzwalane tylko wtedy, gdy użytkownik zamyka okno.

khelll
źródło

Odpowiedzi:

212

beforeunloadZdarzenie pożary, gdy użytkownik opuszcza stronę z jakiegokolwiek powodu.

Na przykład zostanie uruchomiony, jeśli użytkownik wyśle ​​formularz, kliknie łącze, zamknie okno (lub kartę) lub przejdzie do nowej strony za pomocą paska adresu, pola wyszukiwania lub zakładki.

Możesz wykluczyć przesyłanie formularzy i hiperłącza (z wyjątkiem innych ramek) za pomocą następującego kodu:

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

W przypadku wersji jQuery starszych niż 1.7 spróbuj tego:

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

Ta livemetoda nie działa ze submitzdarzeniem, więc jeśli dodasz nowy formularz, będziesz musiał również powiązać z nim procedurę obsługi.

Zauważ, że jeśli inny program obsługi zdarzeń anuluje przesyłanie lub nawigację, utracisz monit o potwierdzenie, jeśli okno zostanie faktycznie zamknięte później. Można to naprawić poprzez rejestrowanie czasu w submiti clickwydarzeń, a także sprawdzanie, czy beforeunloaddzieje się więcej niż kilka sekund później.

SLaks
źródło
8
tak, działa świetnie! Nowsze wersje jquery obsługują $ ('form'). Live ('submit, function () {}).
Venkat D.,
4
Twoje rozwiązanie jest dobre, ale jak anulować wydarzenie w przypadku odświeżenia? Chcę wydarzenie tylko wtedy, gdy przeglądarka jest zamknięta, bez przypadku odświeżania
Refael
Wygląda na to, że przeglądarka wyświetla wartość zwracaną przez beforeunload jako okno dialogowe potwierdzenia. Myślę więc, że ta odpowiedź jest dokładniejsza: link
tahagh
2
Czyni to uchwyt odświeżania strony za pomocą Ctrl + r, F5, Ctrl + Shift + ri zmieniając adres URL w przeglądarce?
Arti
1
@Jonny: Teraz jest po prostu .on().
SLaks
45

Może po prostu usuń powiązanie programu beforeunloadobsługi zdarzeń w module obsługi zdarzeń formularza submit:

jQuery('form').submit(function() {
    jQuery(window).unbind("beforeunload");
    ...
});
karim79
źródło
3
Czy nie jest to równie łatwe, jeśli nie używasz jQuery, określając to w definicji tagu formularza? : `<form onsubmit =" window.onbeforeunload = null; ">
awe
4
@awe Ale musisz to uwzględnić onsubmit=...w każdej formie. (Mam wiele formularzy na stronie, w określonej aplikacji internetowej)
KajMagnus
16

W przypadku rozwiązania obsługującego wiele przeglądarek (przetestowanego w Chrome 21, IE9, FF15) rozważ użycie następującego kodu, który jest nieco zmodyfikowaną wersją kodu Slaksa:

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

Zwróć uwagę, że od wersji Firefox 4 pojawia się komunikat „Czy na pewno chcesz zamknąć?” nie jest wyświetlany. FF wyświetla tylko ogólny komunikat. Zobacz notatkę w https://developer.mozilla.org/en-US/docs/DOM/window.onbeforeunload

desm
źródło
3
Ten działa konsekwentnie w różnych przeglądarkach. Tylko krótka notatka; Zaktualizowałem zarówno instrukcje, jak livei bindinstrukcje do on, co działa świetnie z najnowszym poziomem jQuery. Dzięki!
Sablefoste
16
window.onbeforeunload = function () {
    return "Do you really want to close?";
};
Behnam Mohammadi
źródło
4

Aby uzyskać rozwiązanie, które działało dobrze z kontrolkami innych firm, takimi jak Telerik (np .: RadComboBox) i DevExpress, które używają znaczników Anchor z różnych powodów, rozważ użycie następującego kodu, który jest nieco zmodyfikowaną wersją kodu desm z lepszym selektorem dla siebie kierowanie na tagi kotwicy:

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;
});
PLT
źródło
1
Ta odpowiedź jest poprawna, ale dla tych, którzy mieli problemy z tym wydarzeniem występującym po odświeżeniu przeglądarki, zmień swoje if na następujący kod: if (inFormOrLink! == undefined &&! InFormOrLink)
LeonPierre
4

Moja odpowiedź ma na celu przedstawienie prostych wzorców.

JAK

Zobacz odpowiedź @SLaks .

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

Jak długo trwa przeglądarka, aby ostatecznie zamknąć stronę?

Za każdym razem, gdy użytkownik zamyka stronę ( xprzycisk lub CTRL+ W), przeglądarka wykonuje podany beforeunloadkod, ale nie w nieskończoność. Jedynym wyjątkiem jest okienko potwierdzenia ( return 'Do you really want to close?), które będzie czekać na odpowiedź użytkownika.

Chrome : 2 sekundy.
Firefox : ∞ (lub kliknij dwukrotnie lub wymuś zamknięcie)
Edge : ∞ (lub kliknij dwukrotnie)
Explorer 11 : 0 sekund.
Safari : TODO

Co wykorzystaliśmy do przetestowania tego:

  • Serwer Node.js Express z dziennikiem żądań
  • Poniższy krótki plik HTML

To, co robi, to wysłanie jak największej liczby żądań, zanim przeglądarka zamknie swoją stronę (synchronicznie).

<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>

Wyjście 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.
zurfyx
źródło
3

Użyłem odpowiedzi Slaks, ale to nie działało tak, jak jest, ponieważ wartość returnValue onbeforeunload jest analizowana jako ciąg, a następnie wyświetlana w polu potwierdzeń przeglądarki. Została więc wyświetlona wartość true, np. „True”.

Po prostu użycie zwrotu zadziałało. Oto mój kod

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;
})
kapad
źródło
1

Być może mógłbyś obsłużyć OnSubmit i ustawić flagę, którą później sprawdzisz w programie obsługi OnBeforeUnload.

i_am_jorf
źródło
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?";
                          }
                      })
Kodowanie człowieka
źródło
1

Niestety, niezależnie od tego, czy jest to przeładowanie, przekierowanie nowej strony, czy zamknięcie przeglądarki, zdarzenie zostanie wywołane. Alternatywą jest złapanie identyfikatora wyzwalającego zdarzenie, a jeśli jest to forma, nie wyzwalaj żadnej funkcji, a jeśli nie jest to identyfikator formularza, zrób to, co chcesz zrobić po zamknięciu strony. Nie jestem pewien, czy jest to również możliwe bezpośrednio i nużące.

Możesz zrobić kilka drobnych rzeczy, zanim klient zamknie kartę. javascript wykrywa przeglądarkę zamknij kartę / zamknij przeglądarkę, ale jeśli lista działań jest duża, a karta zamyka się przed jej zakończeniem, jesteś bezradny. Możesz spróbować, ale z moim doświadczeniem nie polegaj na tym.

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

Gary
źródło
0

Jeśli przesłanie formularza przenosi ich na inną stronę (jak zakładam, stąd wyzwolenie beforeunload), możesz spróbować zmienić przesyłanie formularza na wywołanie Ajax. W ten sposób nie opuszczą Twojej strony, gdy prześlą formularz, a Ty możesz użyć swojego beforeunloadkodu wiążącego, jak chcesz.

idrumgood
źródło
0

Mój problem: zdarzenie „onbeforeunload” byłoby wywoływane tylko w przypadku nieparzystej liczby zgłoszeń (kliknięć). Miałem kombinację rozwiązań z podobnych wątków w SO, aby moje rozwiązanie działało. mój kod będzie mówił.

<!--The definition of event and initializing the trigger flag--->


$(document).ready(function() {
updatefgallowPrompt(true);
window.onbeforeunload = WarnUser;   
}

function WarnUser() {
var allowPrompt = getfgallowPrompt();
    if(allowPrompt) {
    saveIndexedDataAlert();
    return null;
    } else {
        updatefgallowPrompt(true);
        event.stopPropagation
    }
}

<!--The method responsible for deciding weather the unload event is triggered from submit or not--->
function saveIndexedDataAlert() {
    var allowPrompt = getfgallowPrompt();
    var lenIndexedDocs = parseInt($('#sortable3 > li').size()) + parseInt($('#sortable3 > ul').size());

    if(allowPrompt && $.trim(lenIndexedDocs) > 0) {
        event.returnValue = "Your message";
    } else {
        event.returnValue = "   ";
        updatefgallowPrompt(true);
    }
}

<!---Function responsible to reset the trigger flag---->
$(document).click(function(event) {  
$('a').live('click', function() { updatefgallowPrompt(false); });
 });

<!--getter and setter for the flag---->
function updatefgallowPrompt (allowPrompt){ //exit msg dfds
    $('body').data('allowPrompt', allowPrompt); 
}   

function getfgallowPrompt(){        
    return $('body').data('allowPrompt');   
}
Yoosaf Abdulla
źródło
0

Od jQuery 1.7 metoda .live () jest przestarzała. Użyj .on (), aby dołączyć programy obsługi zdarzeń. Użytkownicy starszych wersji jQuery powinni używać .delegate () zamiast .live ()

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

po zakończeniu lub linku

$(window).unbind();
Tomek
źródło
0

Spróbuj tego również

window.onbeforeunload = function ()
{       
    if (pasteEditorChange) {
        var btn = confirm('Do You Want to Save the Changess?');
           if(btn === true ){
               SavetoEdit();//your function call
           }
           else{
                windowClose();//your function call
           }
    }  else { 
        windowClose();//your function call
    }
};
Bhaskara Arani
źródło
-1

Po prostu zweryfikuj ...

function wopen_close(){
  var w = window.open($url, '_blank', 'width=600, height=400, scrollbars=no, status=no, resizable=no, screenx=0, screeny=0');
  w.onunload = function(){
    if (window.closed) {
       alert("window closed");
    }else{ 
       alert("just refreshed");
    }
  }
}
Brunno
źródło
To nie działa. W tej chwili uruchamia się zdarzenie rozładowania (przy okazji, jest uruchamiane z dokumentu), okno.closed === false;
Sergey P. alias lazur
-1
var validNavigation = false;
            jQuery(document).ready(function () {

                wireUpEvents();
            });

            function endSession() {
                // Browser or broswer tab is closed
                // Do sth here ...
                alert("bye");
            }

            function wireUpEvents() {
                /*
                * For a list of events that triggers onbeforeunload on IE
                * check http://msdn.microsoft.com/en-us/library/ms536907(VS.85).aspx
                */
                window.onbeforeunload = function () {
                    debugger
                    if (!validNavigation) {
                        endSession();
                    }
                }

                // Attach the event keypress to exclude the F5 refresh
                $(document).bind('keypress', function (e) {
                    debugger
                    if (e.keyCode == 116) {
                        validNavigation = true;
                    }
                });

                // Attach the event click for all links in the page
                $("a").bind("click", function () {
                    debugger
                    validNavigation = true;
                });

                // Attach the event submit for all forms in the page
                $("form").bind("submit", function () {
                    debugger
                    validNavigation = true;
                });

                // Attach the event click for all inputs in the page
                $("input[type=submit]").bind("click", function () {
                    debugger
                    validNavigation = true;
                });

            }`enter code here`
arslan khan
źródło
-7

Następujące pracowały dla mnie;

 $(window).unload(function(event) {
    if(event.clientY < 0) {
        //do whatever you want when closing the window..
    }
 });
Dilhan Jayathilaka
źródło
jest to funkcja jQuery.
maxisam
7
Wartość event.clientYjest ujemna, jeśli klikniesz przycisk zamykania przeglądarki lub przycisk zamykania karty. Jednak ta wartość jest dodatnia po ponownym załadowaniu strony za pomocą skrótów klawiaturowych (F5, Ctrl-R) lub zamknięciu przeglądarki za pomocą skrótów klawiaturowych (np. Alt-F4). Dlatego nie można polegać na pozycji zdarzenia w celu odróżnienia zdarzenia zamknięcia przeglądarki od zdarzenia ponownego załadowania strony.
Julien Kronegg,