Abfangen des Seitenabbruchereignisses

117

Beim Bearbeiten einer Seite in meinem System kann ein Benutzer entscheiden, zu einer anderen Website zu navigieren, und dabei alle Änderungen verlieren, die er nicht gespeichert hat.

Ich möchte jeden Versuch abfangen, zu einer anderen Seite zu wechseln und den Benutzer aufzufordern, sicherzugehen, dass dies geschehen soll, da er möglicherweise seine aktuelle Arbeit verlieren könnte.

Google Mail tut dies auf sehr ähnliche Weise. Erstellen Sie beispielsweise eine neue E-Mail, geben Sie sie in den Nachrichtentext ein und geben Sie einen neuen Speicherort in die Adressleiste ein (z. B. twitter.com oder ähnliches). Sie werden gefragt, ob Sie sicher sind.

Ideen, wie man das repliziert? Ich ziele auf IE8 ab, möchte aber auch mit FF & Chrome kompatibel sein.

Chris Ballance
quelle

Antworten:

153

Ähnlich wie Ghommeys Antwort, unterstützt dies jedoch auch alte Versionen von IE und Firefox.

window.onbeforeunload = function (e) {
  var message = "Your confirmation message goes here.",
  e = e || window.event;
  // For IE and Firefox
  if (e) {
    e.returnValue = message;
  }

  // For Safari
  return message;
};
Eli Gray
quelle
1
Könnten Sie die erste Zeile erklären (var message = ...)? Ich weiß nicht, was dieses Komma und der zweite Ausdruck tun.
Mtmurdock
7
@mtmurdock Das ist nur Javascript-Syntax, um mehrere Variablen zu deklarieren. var foo, bar;ist das gleiche wievar foo; var bar;
T Nguyen
4
@mtmurdock, Die zweite Anweisung " var e = e || window.event;" bedeutet, dass e gleich dem Parameter e (wenn es wahr ist) oder window.event ist, wenn es nicht wahr ist. Es ist nicht wahr, wenn der Parameter e null ist.
T Nguyen
3
@Blieque addEventListener wird in IE8 nicht unterstützt. Bearbeiten Sie die Antworten von Personen nicht, ohne die Frage zu lesen.
Eli Gray
2
Funktioniert nicht mehr in Chrome (veraltet): developer.google.com/web/updates/2016/04/…
Micha Schwab
25

Siehe diesen Artikel. Die Funktion, nach der Sie suchen, ist das Onbeforeunload

Beispielcode:

  <script language="JavaScript">
  window.onbeforeunload = confirmExit;
  function confirmExit()
  {
    return "You have attempted to leave this page.  If you have made any changes to the fields without clicking the Save button, your changes will be lost.  Are you sure you want to exit this page?";
  }
</script>
jantimon
quelle
2
Gibt es eine Möglichkeit festzustellen, dass der Benutzer die Option "Diese Seite verlassen" anstelle von "Auf dieser Seite bleiben" ausgewählt hat?
Shilpa Soni
@ShilpaSoni Sie würden in Kürze ein nachfolgendes Entladeereignis erhalten, developer.mozilla.org/en-US/docs/Web/API/Window/unload_event, aber ich glaube nicht, dass es einen synchronen Weg gibt.
Scipilot
6

Anstelle eines nervigen Bestätigungs-Popups wäre es schön, die Verzögerung ein wenig (innerhalb von Millisekunden) zu verzögern , um das erfolgreiche Posten der nicht gespeicherten Daten auf dem Server zu verwalten, den ich für meine Site verwaltet habe, indem ich Dummy-Text wie folgt auf die Konsole geschrieben habe:

window.onbeforeunload=function(e){
  // only take action (iterate) if my SCHEDULED_REQUEST object contains data        
  for (var key in SCHEDULED_REQUEST){   
    postRequest(SCHEDULED_REQUEST); // post and empty SCHEDULED_REQUEST object
    for (var i=0;i<1000;i++){
      // do something unnoticable but time consuming like writing a lot to console
      console.log('buying some time to finish saving data'); 
    };
    break;
  };
}; // no return string --> user will leave as normal but data is send to server

Bearbeiten: Siehe auch Synchronous_AJAX und wie das mit jquery geht

Remi
quelle
Ich mag diese Alternative zum Popup. Danke für den Vorschlag, Remi.
Chris Ballance
2
das macht absolut keinen Sinn -1. Javascript ist kein Thread. Sie führen eine postRequest durch und unterbrechen dann die Berechnung der Site, ohne dass niemand etwas tun darf (einschließlich Ihrer postRequest, die inzwischen bereits vor der Berechnungspause gesendet wurde).
FMSF
Und genau deshalb funktioniert es: Die Post-Anfrage wurde zwar vor der Berechnungspause gesendet, aber diese kleine Blockierung der Seite, bevor sie tatsächlich verlassen wird, stellt sicher, dass der Browser-Client (nicht Javascript) genügend Zeit hat, um diese Anfrage ordnungsgemäß zu senden . Ich habe festgestellt, dass die Anfrage nicht immer gesendet wird, wenn ich nur die Anfrage sende (ohne zu blockieren) und die Seite sofort danach verlasse.
Remi
6
Das würde ich in der Produktion nicht verwenden. console.log ist kein Crossbrowser. Jede postRequest leidet unter der Verzögerung der vorherigen (was auch bedeutet, dass die Seite dort für die Dauer Ihrer geplanten Schleife * -Anfragen hängen bleibt). Die Anforderungen werden nicht parallel gestartet. Es ist nicht garantiert, dass Sie Ihre Anfragen wirklich senden. Wenn ich gezwungen wäre, mich mit diesem Problem auseinanderzusetzen, würde ich mit einer synchronen Ajax-Anfrage gehen, wenn es nur eine Anfrage gibt. Bei mehreren Anforderungen würde ich asynchrone Ajax-Anforderungen und eine Schleife verwenden, die die Ergebnisse (entweder Erfolg oder Fehler) von Rückrufen der Anforderungen überprüft.
Framp
Ich wusste nicht, dass console.log nicht browserübergreifend ist und eine synchrone Ajax-Anfrage tatsächlich die bevorzugte Lösung sein sollte (für eine einzelne Anfrage). Das erwähnte SCHEDULED_REQUESTObjekt sammelt alle nicht dringenden Informationen, die wie ein Datenpuffer an den Server gesendet werden sollen, und verbindet effektiv mehrere Anforderungen mit einer (natürlich ist die URL dieser Anforderungen dieselbe). Die Verwendung einer synchronen Ajax-Anforderung vor dem Entladen sollte das Problem, wie gesagt, browserübergreifend lösen. Vielen Dank für Ihren wertvollen Kommentar!
Remi
0

Ich habe Benutzer, die nicht alle erforderlichen Daten ausgefüllt haben.

<cfset unloadCheck=0>//a ColdFusion precheck in my page generation to see if unload check is needed
var erMsg="";
$(document).ready(function(){
<cfif q.myData eq "">
    <cfset unloadCheck=1>
    $("#myInput").change(function(){
        verify(); //function elsewhere that checks all fields and populates erMsg with error messages for any fail(s)
        if(erMsg=="") window.onbeforeunload = null; //all OK so let them pass
        else window.onbeforeunload = confirmExit(); //borrowed from Jantimon above;
    });
});
<cfif unloadCheck><!--- if any are outstanding, set the error message and the unload alert --->
    verify();
    window.onbeforeunload = confirmExit;
    function confirmExit() {return "Data is incomplete for this Case:"+erMsg;}
</cfif>
Gordon
quelle