Wie kann ich den OnBeforeUnload-Dialog überschreiben und durch meinen eigenen ersetzen?

346

Ich muss Benutzer vor nicht gespeicherten Änderungen warnen, bevor sie eine Seite verlassen (ein ziemlich häufiges Problem).

window.onbeforeunload=handler

Dies funktioniert, aber es wird ein Standarddialog mit einer irritierenden Standardnachricht ausgelöst, die meinen eigenen Text umschließt. Ich muss entweder die Standardnachricht vollständig ersetzen, damit mein Text klar ist, oder (noch besser) den gesamten Dialog durch einen modalen Dialog mit jQuery ersetzen.

Bisher habe ich versagt und ich habe niemanden gefunden, der eine Antwort zu haben scheint. Ist es überhaupt möglich?

Javascript auf meiner Seite:

<script type="text/javascript">   
   window.onbeforeunload=closeIt;
</script>

Die Funktion closeIt ():

function closeIt()
{
  if (changes == "true" || files == "true")
  {
      return "Here you can append a custom message to the default dialog.";
  }
}

Mit jQuery und jqModal habe ich Folgendes versucht (mithilfe eines benutzerdefinierten Bestätigungsdialogs):

$(window).beforeunload(function() {
        confirm('new message: ' + this.href + ' !', this.href);
        return false;
    });

was auch nicht funktioniert - ich kann mich anscheinend nicht an das Ereignis beforeunload binden.

Fleisch
quelle
1
Können Sie ein Beispiel für Ihren aktuellen Code geben und was er erzeugt?
Owen
Owen ist richtig. Und der Grund dafür ist die Sicherheit. Das Verhindern des Entladens einer Seite ist in Webformularen und dergleichen nützlich, kann jedoch leicht von einer böswilligen Website ausgenutzt werden, um den Benutzer dazu zu bringen, auf einer Seite zu bleiben. Aus diesem Grund implementieren Webbrowser die Standardnachricht und verfügen über diesen Mechanismus zum Einfügen von benutzerdefiniertem Text.
Pluckyglen
Weitere Informationen finden Sie hier: stackoverflow.com/questions/140460
Ben McIntyre
1
nicht in Chrom möglich, Referenz: stackoverflow.com/questions/37782104/…
Abhijeet

Antworten:

299

Sie können den Standarddialog für nicht ändern onbeforeunload, daher ist es möglicherweise am besten, damit zu arbeiten.

window.onbeforeunload = function() {
    return 'You have unsaved changes!';
}

Hier ist ein Verweis von Microsoft:

Wenn der returnValue-Eigenschaft von window.event eine Zeichenfolge zugewiesen wird, wird ein Dialogfeld angezeigt, in dem Benutzer auf der aktuellen Seite bleiben und die ihr zugewiesene Zeichenfolge beibehalten können. Die im Dialogfeld angezeigte Standardanweisung "Möchten Sie wirklich von dieser Seite weg navigieren? ... Drücken Sie OK, um fortzufahren, oder Abbrechen, um auf der aktuellen Seite zu bleiben." Kann nicht entfernt oder geändert werden.

Das Problem scheint zu sein:

  1. Wenn onbeforeunloades aufgerufen wird, wird der Rückgabewert des Handlers als angenommen window.event.returnValue.
  2. Der Rückgabewert wird dann als Zeichenfolge analysiert (es sei denn, er ist null).
  3. Da falsees als Zeichenfolge analysiert wird, wird das Dialogfeld ausgelöst, das dann ein entsprechendes true/ übergibt false.

Das Ergebnis ist, es scheint keine Möglichkeit der Zuordnung zu sein , falseum onbeforeunloades aus dem Standard - Dialog zu verhindern.

Zusätzliche Hinweise zu jQuery:

  • Das Festlegen des Ereignisses in jQuery kann problematisch sein, da dadurch auch andere onbeforeunloadEreignisse auftreten können. Wenn Sie nur möchten, dass Ihr Entladeereignis auftritt, würde ich mich an das einfache alte JavaScript halten.
  • jQuery hat keine Verknüpfung für, onbeforeunloaddaher müssten Sie die generische bindSyntax verwenden.

    $(window).bind('beforeunload', function() {} );

Bearbeiten 2018.09.04 : benutzerdefinierte Nachrichten in onbeforeunload Dialoge sind veraltet , da Chrom-51 (siehe dazu : Release-Info )

Owen
quelle
20
Ich habe festgestellt, dass das JQuery-Beispiel am Ende nicht in Firefox funktioniert. Halten Sie sich stattdessen an den einfachen Weg: window.onbeforeunload = function () {...}
jb.
21
Nur ein Hinweis, dass Firefox kürzlich geändert wurde, so dass der Text im Dialogfeld nicht einmal angepasst werden kann: bugzilla.mozilla.org/show_bug.cgi?id=588292
David Hammond
15
Aber wie bietet Facebook dann ein benutzerdefiniertes Dialogfeld? Gehen Sie beispielsweise zur Nachrichtenseite, antworten Sie auf die Nachricht Ihres Freundes und versuchen Sie dann, bevor Sie auf Senden klicken, auf einen anderen Link zu klicken. Sie sehen ein benutzerdefiniertes Dialogfeld Popup
Varun
20
@Varun - alte Nachrichten, aber Facebook setzt möglicherweise Handler auf das Klickereignis aller ihrer Anker. Wenn Sie jedoch die URL im Browser neu schreiben oder das Fenster schließen, wird die Standardmethode wiederhergestellt, über die sie keine Kontrolle haben.
Tabloo Quijico
1
@Varun Ich bin auch überrascht, dass diese Antwort, die unmöglich ist, als Antwort gekennzeichnet ist und 150 positive Stimmen hat ... Gerade erkannt, dass die benutzerdefinierte Nachricht von FB nur über Links auf ihrer Website verfügbar ist. Nicht, wenn Sie einfach weg navigieren ...
Sébastien Richer
28

Was für mich mit jQuery funktioniert und in IE8, Chrome und Firefox getestet wurde, ist:

$(window).bind("beforeunload",function(event) {
    if(hasChanged) return "You have unsaved changes";
});

Es ist wichtig, nichts zurückzugeben, wenn keine Eingabeaufforderung erforderlich ist, da hier Unterschiede zwischen dem IE und anderen Browserverhalten bestehen.

Haubentaucher
quelle
Interessant event.returnValueist die einzige "genehmigte" Methode im IE. Der IE fährt fort: "Der Wert dieser Eigenschaft hat Vorrang vor den von der Funktion zurückgegebenen Werten, z. B. über eine Microsoft JScript-Rückgabeanweisung." .. es wäre schön, eine garantierte Korrelation zwischen return(vom Ereignis) und event.returnValue..
21

Obwohl Sie unter bestimmten Umständen nichts gegen die Box unternehmen können, können Sie jemanden abfangen, der auf einen Link klickt. Für mich war dies für die meisten Szenarien die Mühe wert und als Fallback habe ich das Entladeereignis verlassen.

Ich habe Boxy anstelle des Standard-jQuery-Dialogs verwendet. Es ist hier verfügbar: http://onehackoranother.com/projects/jquery/boxy/

$(':input').change(function() {
    if(!is_dirty){
        // When the user changes a field on this page, set our is_dirty flag.
        is_dirty = true;
    }
});

$('a').mousedown(function(e) {
    if(is_dirty) {
        // if the user navigates away from this page via an anchor link, 
        //    popup a new boxy confirmation.
        answer = Boxy.confirm("You have made some changes which you might want to save.");
    }
});

window.onbeforeunload = function() {
if((is_dirty)&&(!answer)){
            // call this if the box wasn't shown.
    return 'You have made some changes which you might want to save.';
    }
};

Sie können an ein anderes Ereignis anhängen und mehr nach der Art des Ankers filtern, auf den geklickt wurde. Dies funktioniert jedoch für mich und meine Aufgaben und dient anderen als Beispiel für die Verwendung oder Verbesserung. Ich dachte, ich würde dies für diejenigen teilen, die diese Lösung wollen.

Ich habe Code ausgeschnitten, daher funktioniert dies möglicherweise nicht so wie er ist.

Dan Power
quelle
return 'Sie haben einige Änderungen vorgenommen, die Sie möglicherweise speichern möchten.' hat bei mir nicht funktioniert. Ich musste die Nachricht in einer Variablen namens "warning_message" speichern und gab warning_message zurück. Dann hat es nur bei mir geklappt!.
Suganya
Haben Sie in IE, Chrome, Firefox getestet?
Kiquenet
9

1) Verwenden Sie onbeforeunload, nicht onunload.

2) Wichtig ist, dass keine return-Anweisung ausgeführt wird. Damit meine ich nicht, dass Sie nicht von Ihrem Handler zurückkehren. Sie geben alles in Ordnung zurück, aber Sie tun dies, indem Sie sicherstellen, dass Sie das Ende der Funktion erreichen und KEINE return-Anweisung ausführen. Unter diesen Bedingungen tritt der integrierte Standarddialog nicht auf.

3) Wenn Sie onbeforeunload verwenden, können Sie einen Ajax-Aufruf in Ihrem unbforeunload-Handler ausführen, um den Server aufzuräumen. Er muss jedoch synchron sein, und Sie müssen auf die Antwort in Ihrem onbeforeunload-Handler warten und sie verarbeiten (immer noch respektierend) Bedingung (2) oben). Ich mache das und es funktioniert gut. Wenn Sie einen synchronen Ajax-Anruf tätigen, wird alles angehalten, bis die Antwort zurückkommt. Wenn Sie eine asynchrone Aktion ausführen und der Meinung sind, dass Ihnen die Antwort vom Server egal ist, wird das Entladen der Seite fortgesetzt und Ihr Ajax-Aufruf wird durch diesen Vorgang abgebrochen - einschließlich eines Remote-Skripts, falls es ausgeführt wird.

user1164763
quelle
Nur zu Ihrer
Information,
4

Versuchen Sie, eine return;anstelle einer Nachricht zu platzieren. Dies funktioniert in den meisten Browsern für mich. (Dies verhindert nur wirklich die Geschenke des Dialogs)

window.onbeforeunload = function(evt) {            
        //Your Extra Code
        return;
}
Donald Powell
quelle
3
return null verhindert das Öffnen des Dialogs
Brett Weber
1
return null verhindert NICHT, dass der Dialog geöffnet wird. Ich habe es in Chrome versucht und es ist nicht der Fall.
Ray
2
Ich kann Rays Kommentar auch im IE bestätigen. Wenn Sie zurückkehren, nullwird ein Dialogfeld mit dem Text "null" geöffnet. Der return void(0);Dialog wird jedoch nicht geöffnet.
MCattle
1
Wenn Sie keine return-Anweisung in die Funktion beforeunload einfügen, wird der Dialog nicht geöffnet.
OuuGiii
3

Sie können erkennen, welche Taste (OK oder Abbrechen) vom Benutzer gedrückt wurde, da die Onunload-Funktion nur aufgerufen wird, wenn der Benutzer die Seite verlässt. Obwohl in dieser Funktion die Möglichkeiten begrenzt sind, weil das DOM zusammengebrochen wird. Sie können Javascript ausführen, aber der Ajax-POST macht nichts, daher können Sie diese Methode nicht für die automatische Abmeldung verwenden. Dafür gibt es aber eine Lösung. Die window.open ('logout.php') wird in der Onunload-Funktion ausgeführt, sodass sich der Benutzer mit einer neuen Fensteröffnung abmeldet.

function onunload = (){
    window.open('logout.php');
}

Dieser Code wird aufgerufen, wenn der Benutzer die Seite verlässt oder das aktive Fenster schließt und sich mit 'logout.php' abmeldet. Das neue Fenster wird sofort geschlossen, wenn Logout-PHP aus Code besteht:

window.close();
Tamas Cseh
quelle
Sie können einen synchronen Beitrag in den Funktionen vor dem Entladen und Entladen verwenden. Vor allem, wenn Sie Daten vom Server zurück benötigen. Asynchroner Code in diesen Blöcken wird zum Zeitpunkt des Entladens der Seite möglicherweise nicht abgeschlossen.
jemiloii
3

Ich hatte das gleiche Problem, ich war in Ordnung, ein eigenes Dialogfeld mit meiner Nachricht zu erhalten, aber das Problem, mit dem ich konfrontiert war, war: 1) Es gab eine Nachricht bei allen Navigationen, die ich nur zum Schließen möchte. 2) Wenn der Benutzer mit meiner eigenen Bestätigungsnachricht Abbrechen auswählt, wird weiterhin das Standarddialogfeld des Browsers angezeigt.

Es folgt der Lösungscode, den ich gefunden habe und den ich auf meiner Masterseite geschrieben habe.

function closeMe(evt) {
    if (typeof evt == 'undefined') {
        evt = window.event; }
    if (evt && evt.clientX >= (window.event.screenX - 150) &&
        evt.clientY >= -150 && evt.clientY <= 0) {
        return "Do you want to log out of your current session?";
    }
}
window.onbeforeunload = closeMe;
Imran Rizvi
quelle
1
 <script type="text/javascript">
        window.onbeforeunload = function(evt) {
            var message = 'Are you sure you want to leave?';
            if (typeof evt == 'undefined') {
                evt = window.event;
            }       
            if (evt) {
                evt.returnValue = message;
            }
            return message;
        } 
    </script>

Weitere Informationen finden Sie unter http://www.codeprojectdownload.com

Krishna Patel
quelle
1

Was ist mit der speziellen Version des Befehls "bind" "one"? Sobald der Ereignishandler das erste Mal ausgeführt wird, wird er automatisch als Ereignishandler entfernt.

$(window).one("beforeunload", BeforeUnload);
Riga
quelle
ziemlich sicher, dass dies .on ist ("beforeunload"
Sergiu Mindras
2
@SergiuMindras nein, es ist .one()- das fügt einen Ereignis-Listener hinzu, um darauf zu warten, dass das Ereignis nur einmal auftritt: "Hängen Sie einen Handler an ein Ereignis für die Elemente an. Der Handler wird höchstens einmal pro Element und Ereignistyp ausgeführt." api.jquery.com/one
Sean Kendle
0

Winkel 9 Ansatz:

constructor() {
    window.addEventListener('beforeunload', (event: BeforeUnloadEvent) => {
     if (this.generatedBarcodeIndex) {
      event.preventDefault(); // for Firefox
      event.returnValue = ''; // for Chrome
      return '';
     }
     return false;
    });
   }

Browserunterstützung und Entfernen der benutzerdefinierten Nachricht:

  • Chrome hat die Unterstützung für die benutzerdefinierte Nachricht in Version 51 Minuten entfernt
  • Opera hat die Unterstützung für die benutzerdefinierte Nachricht in Version 38 Minuten entfernt
  • Firefox hat die Unterstützung für die benutzerdefinierte Nachricht in Version 44.0 min entfernt
  • Safari hat die Unterstützung für die benutzerdefinierte Nachricht in Version 9.1 min entfernt
Istvan Dembrovszky
quelle