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.

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.


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

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


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


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

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.

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

1

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


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

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


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.


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

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

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

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

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`

-7

Następujące pracowały dla mnie;

 $(window).unload(function(event) {
    if(event.clientY < 0) {
        //do whatever you want when closing the window..
    }
 });

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,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.