Warnen Sie den Benutzer, bevor Sie die Webseite mit nicht gespeicherten Änderungen verlassen


340

Ich habe einige Seiten mit Formularen in meiner Bewerbung.

Wie kann ich das Formular so sichern, dass jemand, der weg navigiert oder den Browser-Tab schließt, aufgefordert werden sollte, zu bestätigen, dass er das Formular wirklich mit nicht gespeicherten Daten verlassen möchte?



3
Diese Frage hier sollte die Antwort haben, nach der Sie suchen
Nexerus


Antworten:


556

Kurze, falsche Antwort:

Sie können dies tun, indem Sie das beforeunloadEreignis behandeln und eine Nicht-Null-Zeichenfolge zurückgeben :

window.addEventListener("beforeunload", function (e) {
    var confirmationMessage = 'It looks like you have been editing something. '
                            + 'If you leave before saving, your changes will be lost.';

    (e || window.event).returnValue = confirmationMessage; //Gecko + IE
    return confirmationMessage; //Gecko + Webkit, Safari, Chrome etc.
});

Das Problem bei diesem Ansatz besteht darin, dass beim Senden eines Formulars auch das Entladeereignis ausgelöst wird . Dies lässt sich leicht beheben, indem Sie ein Flag hinzufügen, mit dem Sie ein Formular senden:

var formSubmitting = false;
var setFormSubmitting = function() { formSubmitting = true; };

window.onload = function() {
    window.addEventListener("beforeunload", function (e) {
        if (formSubmitting) {
            return undefined;
        }

        var confirmationMessage = 'It looks like you have been editing something. '
                                + 'If you leave before saving, your changes will be lost.';

        (e || window.event).returnValue = confirmationMessage; //Gecko + IE
        return confirmationMessage; //Gecko + Webkit, Safari, Chrome etc.
    });
};

Rufen Sie dann den Setter an, wenn Sie senden:

<form method="post" onsubmit="setFormSubmitting()">     
    <input type="submit" />
</form>

Aber lesen Sie weiter ...

Lange, richtige Antwort:

Sie möchten diese Nachricht auch nicht anzeigen, wenn der Benutzer in Ihren Formularen nichts geändert hat . Eine Lösung besteht darin, das beforeunloadEreignis in Kombination mit einem "schmutzigen" Flag zu verwenden, das die Eingabeaufforderung nur dann auslöst, wenn es wirklich relevant ist.

var isDirty = function() { return false; }

window.onload = function() {
    window.addEventListener("beforeunload", function (e) {
        if (formSubmitting || !isDirty()) {
            return undefined;
        }

        var confirmationMessage = 'It looks like you have been editing something. '
                                + 'If you leave before saving, your changes will be lost.';

        (e || window.event).returnValue = confirmationMessage; //Gecko + IE
        return confirmationMessage; //Gecko + Webkit, Safari, Chrome etc.
    });
};

Um die isDirtyMethode zu implementieren , gibt es verschiedene Ansätze.

Sie können jQuery und Formularserialisierung verwenden , dieser Ansatz weist jedoch einige Mängel auf. Zuerst müssen Sie den Code ändern, damit er in einem beliebigen Formular funktioniert ( $("form").each()funktioniert), aber das größte Problem ist, dass jQuery's serialize()nur für benannte, nicht deaktivierte Elemente funktioniert. Wenn Sie also ein deaktiviertes oder nicht benanntes Element ändern, wird das Dirty-Flag nicht ausgelöst. Hierfür gibt es Problemumgehungen, z. B. das schreibgeschützte Erstellen von Steuerelementen anstelle des Aktivierens, Serialisierens und anschließenden erneuten Deaktivierens der Steuerelemente.

Ereignisse scheinen also der richtige Weg zu sein. Sie können versuchen , auf Tastendrücke zu warten . Diese Veranstaltung hat einige Probleme:

  • Wird nicht bei Kontrollkästchen, Optionsfeldern oder anderen Elementen ausgelöst, die durch Mauseingabe geändert werden.
  • Wird für irrelevante Tastendrücke wie die CtrlTaste ausgelöst .
  • Wird bei Werten, die über JavaScript-Code festgelegt wurden, nicht ausgelöst.
  • Wird beim Ausschneiden oder Einfügen von Text über Kontextmenüs nicht ausgelöst.
  • Funktioniert nicht für virtuelle Eingaben wie Datepicker oder Checkbox- / Radiobutton-Verschönerer, die ihren Wert in einer versteckten Eingabe über JavaScript speichern.

Das changeEreignis wird auch nicht bei Werten ausgelöst, die aus JavaScript-Code festgelegt wurden , und funktioniert daher auch nicht für virtuelle Eingaben.

Das Binden des inputEreignisses an alle inputs (und textareas und selects) auf Ihrer Seite funktioniert in älteren Browsern nicht und unterstützt wie alle oben genannten Ereignisbehandlungslösungen das Rückgängigmachen nicht. Wenn ein Benutzer ein Textfeld ändert und dieses dann rückgängig macht oder ein Kontrollkästchen aktiviert und deaktiviert, wird das Formular weiterhin als fehlerhaft betrachtet.

Und wenn Sie mehr Verhalten implementieren möchten, z. B. bestimmte Elemente ignorieren, haben Sie noch mehr Arbeit zu erledigen.

Das Rad nicht neu erfinden:

Bevor Sie über die Implementierung dieser Lösungen und aller erforderlichen Problemumgehungen nachdenken, stellen Sie fest, dass Sie das Rad neu erfinden und auf Probleme stoßen, die andere bereits für Sie gelöst haben.

Wenn Ihre Anwendung bereits jQuery verwendet, können Sie auch getesteten, gepflegten Code verwenden, anstatt Ihren eigenen zu rollen, und für all dies eine Bibliothek eines Drittanbieters verwenden. jQuery's Bist du sicher? Plugin funktioniert super, siehe ihre Demo-Seite . So einfach ist das:

<script src="jquery.are-you-sure.js"></script>

<script>
  $(function() {
    $('#myForm').areYouSure(
      {
        message: 'It looks like you have been editing something. '
               + 'If you leave before saving, your changes will be lost.'
      }
    );
  });

</script>

Benutzerdefinierte Nachrichten werden nicht überall unterstützt

Beachten Sie, dass Firefox 4 in diesem Dialogfeld keine benutzerdefinierten Nachrichten unterstützt. Ab April 2016 wird Chrome 51 eingeführt, in dem auch benutzerdefinierte Nachrichten entfernt werden .

Einige Alternativen gibt es an anderer Stelle auf dieser Website, aber ich denke, ein Dialog wie dieser ist klar genug:

Möchten Sie diese Seite verlassen?

Von Ihnen vorgenommene Änderungen werden möglicherweise nicht gespeichert.

Leave Stay


6
Beachten Sie, dass die Verwendung benutzerdefinierter Zeichenfolgen in Chrome nicht mehr funktioniert. chromestatus.com/feature/5349061406228480
amann

5
Ja, das ist im letzten Abschnitt meiner Antwort beschrieben.
CodeCaster

2
@Chris Das liegt daran, dass Angular das DOM manipuliert, um die Seite zu ändern, ohne vom aktuellen Dokument weg zu navigieren.
CodeCaster

15
Seien Sie gewarnt, jQuery areYouSure wurde seit 2014 aufgegeben (57 offene Ausgaben auf Github ). Es ist voller Fehler aus meiner Erfahrung. Es scheint zunächst zu funktionieren, aber nach einigen kurzen Tests wurde mir klar, dass es nicht immer funktioniert. Würde das überhaupt nicht empfehlen
Mark

4
@JacopoStanchi Ich habe leider keine gefunden. Und ich meine, ich habe ziemlich viel ausgesehen - aber das war am 10. Januar, also hat vielleicht jemand etwas geschrieben, aber ich bezweifle es. Ihre beste Wette ist es, es selbst zu implementieren - es ist nicht das, was Sie hören möchten, obwohl es Ihnen so leid tut. (Aber zumindest werden Sie keine Überraschungen bekommen, wie ich es mit jQuery areYouSure getan habe.) Und wer weiß, vielleicht könnten Sie es sogar als Open Source machen und Ihre Implementierung würde mit anderen geteilt werden;)
Mark

75

Überprüfen Sie das JavaScript- Ereignis onbeforeunload . Es handelt sich um nicht standardmäßiges JavaScript, das von Microsoft eingeführt wurde. Es funktioniert jedoch in den meisten Browsern und die Dokumentation vor dem Herunterladen enthält weitere Informationen und Beispiele.


3
Ich denke, es ist jetzt Standard geworden. >> Die Veranstaltung wurde ursprünglich von Microsoft in Internet Explorer 4 eingeführt und in der HTML5-Spezifikation standardisiert.
Vee

34

über jquery

$('#form').data('serialize',$('#form').serialize()); // On load save form current state

$(window).bind('beforeunload', function(e){
    if($('#form').serialize()!=$('#form').data('serialize'))return true;
    else e=null; // i.e; if form state change show warning box, else don't show it.
});

Sie können die Google JQuery Form Serialize-Funktion verwenden. Dadurch werden alle Formulareingaben erfasst und im Array gespeichert. Ich denke diese Erklärung ist genug :)


6
Verwenden Sie #form nicht als Formular-ID, da das Fenster ein Objekt mit dem Namen form erstellt :)
mdikici

1
Überprüfen Sie hier, ob es für Sie nicht funktioniert: stackoverflow.com/questions/7080269/…
Leniel Maccaferri

16

Universelle Lösung, die keine Konfiguration erfordert, die automatisch alle Eingabemodifikationen erkennt, einschließlich inhaltsbearbeitbarer Elemente:

"use strict";
(() => {
const modified_inputs = new Set;
const defaultValue = "defaultValue";
// store default values
addEventListener("beforeinput", (evt) => {
    const target = evt.target;
    if (!(defaultValue in target || defaultValue in target.dataset)) {
        target.dataset[defaultValue] = ("" + (target.value || target.textContent)).trim();
    }
});
// detect input modifications
addEventListener("input", (evt) => {
    const target = evt.target;
    let original;
    if (defaultValue in target) {
        original = target[defaultValue];
    } else {
        original = target.dataset[defaultValue];
    }
    if (original !== ("" + (target.value || target.textContent)).trim()) {
        if (!modified_inputs.has(target)) {
            modified_inputs.add(target);
        }
    } else if (modified_inputs.has(target)) {
        modified_inputs.delete(target);
    }
});
// clear modified inputs upon form submission
addEventListener("submit", () => {
    modified_inputs.clear();
    // to prevent the warning from happening, it is advisable
    // that you clear your form controls back to their default
    // state after submission
});
// warn before closing if any inputs are modified
addEventListener("beforeunload", (evt) => {
    if (modified_inputs.size) {
        const unsaved_changes_warning = "Changes you made may not be saved.";
        evt.returnValue = unsaved_changes_warning;
        return unsaved_changes_warning;
    }
});
})();

1
Kühle Bohnen. Kopieren Sie einfach diesen Code, fügen Sie ihn in Ihre Testseite ein, nehmen Sie eine Änderung vor und klicken Sie auf Aktualisieren. Es wird eine native Browser-Warnung angezeigt, die Sie warnt, dass Sie nicht gespeicherte Änderungen vorgenommen haben.
TheLegendaryCopyCoder

1
Dies funktionierte für mich auf Chrome 71.0.3578.98 (Official Build) (64-Bit)
JacobRossDev

2
Dies funktioniert sehr gut, aber wenn Sie dies mit einem Formular zum Senden verwenden, müssen Sie zuerst die festgelegten modifizierten Eingaben löschen, bevor Sie eine Benachrichtigung über bestätigte Änderungen erhalten. Ich habe meinem Formular einen Ereignis-Listener hinzugefügt, um ihn beim Senden aufzurufen, und habe gerade die Set-Funktion clear ausgeführt. Auf diese Weise werden die modifizierten_Eingaben gelöscht, wenn der Ereignis-Listener vor dem Laden ausgeführt wird, und der Beitrag kann fortgesetzt werden.
stepquick

1
Cool tatsächlich kopieren und einfügen. Danke, dass du mir Zeit gespart hast. Arbeite für mich in Firfox 75.0
Connectify_user

1
Ich

10

Aufbauend auf der hervorragenden Idee von Wasim A. , Serialisierung zu verwenden. Das Problem dort war, dass die Warnung auch angezeigt wurde, als das Formular gesendet wurde. Dies wurde hier behoben.

var isSubmitting = false

$(document).ready(function () {
    $('form').submit(function(){
        isSubmitting = true
    })

    $('form').data('initial-state', $('form').serialize());

    $(window).on('beforeunload', function() {
        if (!isSubmitting && $('form').serialize() != $('form').data('initial-state')){
            return 'You have unsaved changes which will not be saved.'
        }
    });
})

Es wurde in Chrome und IE 11 getestet.


Wasim A und Eerik Sven Puudist - Danke, ich habe ID für Formular und ID für meine Schaltfläche zum Speichern verwendet, da alle meine Schaltflächen vom Typ submit <form action = "" id = "Marksform" method = "POST"> <td> <input type = waren "submit" name = "submit_button" id = "save" value = "Save"> </ td> <td> <input type = "submit" name = "submit_button" value = "Next"> </ td> und wenige more all type submit Daher ersetzt .Submit (durch einen bestimmten Klick $ ('# save'). click (function () {isSubmission = true}) Verwenden Sie '#marksform' anstelle von 'form'
Jayanta

7

Basierend auf den vorherigen Antworten und zusammengeschustert von verschiedenen Stellen im Stapelüberlauf, ist hier die Lösung, die ich gefunden habe und die den Fall behandelt, wenn Sie Ihre Änderungen tatsächlich einreichen möchten:

window.thisPage = window.thisPage || {};
window.thisPage.isDirty = false;

window.thisPage.closeEditorWarning = function (event) {
    if (window.thisPage.isDirty)
        return 'It looks like you have been editing something' +
               ' - if you leave before saving, then your changes will be lost.'
    else
        return undefined;
};

$("form").on('keyup', 'textarea', // You can use input[type=text] here as well.
             function () { 
                 window.thisPage.isDirty = true; 
             });

$("form").submit(function () {
    QC.thisPage.isDirty = false;
});
window.onbeforeunload = window.thisPage.closeEditorWarning;

Es ist erwähnenswert, dass IE11 anscheinend erfordert, dass die closeEditorWarningFunktion zurückkehrt, undefineddamit keine Warnung angezeigt wird .


Diese Lösung überprüft nicht, ob Werte von ihrem ursprünglichen Zustand geändert wurden, wodurch sie für den Fall ungültig wird, dass der Benutzer Text eingibt und den eingegebenen Text löscht, bevor er versucht, weg zu navigieren.
Brett Weber

Guter Punkt, @BrettWeber. In diesem Fall können Sie closeEditorWarning ändern und "if (window.thisPage.isDirty && uiHasChanged ())" haben, wobei uiHasChanged eine Funktion ist, die den ursprünglichen Status vom Server kennt und alle Unterschiede überprüft, aber diese Lösung war für Ein Fall, in dem ich nicht besonders viel zusätzliche Arbeit leisten wollte, und dies hat nur dann falsch positive Ergebnisse, wenn in den Textbereichen tatsächliche Tastendrücke vorgenommen wurden, was ich für einen vernünftigen Kompromiss hielt. :)
Jonathan

Sollte nicht QC.thisPage.isDirty = false;sein window.thisPage.isDirty = false;? Auf diese Weise wird überprüft, ob Sie das Formular senden und keine Warnung anzeigen. Schien für meine Tests zu arbeiten. Außerdem haben die meisten Formen inputeher ein als ein textarea. Ich habe folgendes verwendet, was ziemlich gut funktioniert:$("form").on('keyup', 'textarea,input,select', function () {
Mike

7

Der folgende Einzeiler hat für mich gearbeitet.

window.onbeforeunload = s => modified ? "" : null;

Setzen Sie einfach je nach Status Ihrer Anwendung modifiedauf true oder false .


2
Einige Vorschläge: Geben Sie eine benutzerdefinierte Nachricht anstelle einer leeren Zeichenfolge zurück, da diese von einigen Browsern angezeigt wird (z. B. Edge), und geben Sie sie zurück, undefinedanstatt dass der nullIE "null" ausgibt, wenn sie modifiedfalsch ist.
Kevin Lee

1
Wie wäre es mit mobilen Geräten? Mein Verständnis ist, dass iOS-Geräte vor dem Herunterladen nicht berücksichtigt werden.
Jaybro

4

Der folgende Code funktioniert hervorragend. Sie müssen die Eingabeänderungen Ihrer Formularelemente über das ID-Attribut erreichen:

var somethingChanged=false;
            $('#managerForm input').change(function() { 
                somethingChanged = true; 
           }); 
            $(window).bind('beforeunload', function(e){
                if(somethingChanged)
                    return "You made some changes and it's not saved?";
                else 
                    e=null; // i.e; if form state change show warning box, else don't show it.
            });
        });

3
var unsaved = false;
$(":input").change(function () {         
    unsaved = true;
});

function unloadPage() {         
    if (unsaved) {             
        alert("You have unsaved changes on this page. Do you want to leave this page and discard your changes or stay on this page?");
    }
} 
window.onbeforeunload = unloadPage;

Ich habe es in eine separate Datei eingefügt und es in <script src = "warnOnChange.js"> </ script> eingefügt, aber nichts passiert, wenn ich ein Textfeld ändere und dann einen Header-Befehl ausführe.
Fabrizio Bartolomucci

2

Mit serialize () können Sie eine URL-codierte Textzeichenfolge erstellen, indem Sie Formularwerte serialisieren und prüfen, ob sich das Formular vor dem Entladen geändert hat

$(document).ready(function(){
    var form = $('#some-form'),
        original = form.serialize()

    form.submit(function(){
        window.onbeforeunload = null
    })

    window.onbeforeunload = function(){
        if (form.serialize() != original)
            return 'Are you sure you want to leave?'
    }
})

Siehe diesen Link https://coderwall.com/p/gny70a/alert-when-leaving-page-with-unsaved-form Geschrieben von Vladimir Sidorenko


1
Es hat funktioniert, aber wie vom Code-Caster beantwortet, gibt es einige Fehler bei dieser Methode, siehe diese Erklärung stackoverflow.com/a/7317311/10555981
Pradeep

Es gibt bereits einige Antworten serialize(), und tatsächlich hat es seine Nachteile.
CodeCaster

Dies sollte die richtige Antwort sein, sehr einfach zu bedienen und funktioniert wie erwartet.
Jodyshop

1

Wenn Sie der Idee von @codecaster hinzufügen, können Sie dies jeder Seite mit einem Formular hinzufügen (in meinem Fall verwende ich es global, sodass nur auf Formularen diese Warnung angezeigt wird) und seine Funktion in ändern

if ( formSubmitting || document.getElementsByTagName('form').length == 0) 

Setzen Sie auch Formulare ein, einschließlich Login und Links zu Abbrechen-Schaltflächen. Wenn eine Person auf Abbrechen drückt oder das Formular sendet, wird die Warnung nicht auch auf jeder Seite mit einem Formular ausgelöst ...

<a class="btn btn-danger btn-md" href="back/url" onclick="setFormSubmitting()">Cancel</a>

1

Eine ausführliche Erklärung finden Sie hier: http://techinvestigations.redexp.in/comparison-of-form-values-on-load-and-before-close/ Vergleich der Formularwerte beim Laden und -vor-schließen

Der Hauptcode:

function formCompare(defaultValues, valuesOnClose) {

    // Create arrays of property names
    var aPropsFormLoad = Object.keys(defaultValues);
    var aPropsFormClose = Object.keys(valuesOnClose);

    // If number of properties is different,
    // objects are not equivalent
    if (aPropsFormLoad.length != aPropsFormClose.length) {
        return false;
    }

    for (var i = 0; i < aPropsFormLoad.length; i++) {
        var propName = aPropsFormLoad[i];

        // If values of same property are not equal,
        // objects are not equivalent
        if (defaultValues[aPropsFormLoad]+"" !== valuesOnClose[aPropsFormLoad]+"") {
            return false;
        }
    }

    // If we made it this far, objects
    // are considered equivalent
    return true;

}

//add polyfill for older browsers, as explained on the link above

//use the block below on load
    for(i=0; i < document.forms[0].elements.length; i++){
    console.log("The field name is: " + document.forms[0].elements[i].name +
        " and it’s value is: " + document.forms[0].elements[i].value );
    aPropsFormLoad[i] = document.forms[0].elements[i].value;
    }

//create a similar array on window unload event.

//and call the utility function
    if (!formCompare(aPropsOnLoad, aPropsOnClose))
    {
    //perform action: 
    //ask user for confirmation or
    //display message about changes made
    }

1

Kurze Antwort:

let pageModified = true

window.addEventListener("beforeunload", 
  () => pageModified ? 'Close page without saving data?' : null
)

1

Die Lösung von Eerik Sven Puudist ...

var isSubmitting = false;

$(document).ready(function () {
    $('form').submit(function(){
        isSubmitting = true
    })

    $('form').data('initial-state', $('form').serialize());

    $(window).on('beforeunload', function() {
        if (!isSubmitting && $('form').serialize() != $('form').data('initial-state')){
            return 'You have unsaved changes which will not be saved.'
        }
    });
})

... hat die Arbeit für mich spontan in einem komplexen objektorientierten Umfeld erledigt, ohne dass Änderungen erforderlich waren.

Die einzige Änderung, die ich vorgenommen habe, war die Bezugnahme auf das konkrete Formular (nur ein Formular pro Datei) mit dem Namen "formForm" ('form' -> '#formForm'):

<form ... id="formForm" name="formForm" ...>

Besonders gut gelungen ist die Tatsache, dass der Submit-Button "in Ruhe gelassen" wird.

Außerdem funktioniert es bei mir auch mit der neuesten Version von Firefox (Stand 7. Februar 2019).


1

Die universelle Lösung von Eli Grey wurde erst getestet, nachdem ich den Code vereinfacht hatte

  'use strict';
  (() => {
    const modified_inputs = new Set();
    const defaultValue = 'defaultValue';
    // store default values
    addEventListener('beforeinput', evt => {
      const target = evt.target;
      if (!(defaultValue in target.dataset)) {
        target.dataset[defaultValue] = ('' + (target.value || target.textContent)).trim();
      }
    });

    // detect input modifications
    addEventListener('input', evt => {
      const target = evt.target;
      let original = target.dataset[defaultValue];

      let current = ('' + (target.value || target.textContent)).trim();

      if (original !== current) {
        if (!modified_inputs.has(target)) {
          modified_inputs.add(target);
        }
      } else if (modified_inputs.has(target)) {
        modified_inputs.delete(target);
      }
    });

    addEventListener(
      'saved',
      function(e) {
        modified_inputs.clear()
      },
      false
    );

    addEventListener('beforeunload', evt => {
      if (modified_inputs.size) {
        const unsaved_changes_warning = 'Changes you made may not be saved.';
        evt.returnValue = unsaved_changes_warning;
        return unsaved_changes_warning;
      }
    });

  })();

Die Änderungen an seiner werden gelöscht target[defaultValue]und nur target.dataset[defaultValue]zum Speichern des tatsächlichen Standardwerts verwendet.

Und ich habe einen 'gespeicherten' Ereignis-Listener hinzugefügt, in dem das 'gespeicherte' Ereignis von Ihnen selbst ausgelöst wird, wenn Ihre Speicheraktion erfolgreich war.

Diese "universelle" Lösung funktioniert jedoch nur in Browsern, nicht in der Webansicht der App, z. B. in Wechat-Browsern.

Damit es (teilweise) auch in Wechat-Browsern funktioniert, gibt es noch eine weitere Verbesserung:

  'use strict';
  (() => {
    const modified_inputs = new Set();
    const defaultValue = 'defaultValue';
    // store default values
    addEventListener('beforeinput', evt => {
      const target = evt.target;
      if (!(defaultValue in target.dataset)) {
        target.dataset[defaultValue] = ('' + (target.value || target.textContent)).trim();
      }
    });

    // detect input modifications
    addEventListener('input', evt => {
      const target = evt.target;
      let original = target.dataset[defaultValue];

      let current = ('' + (target.value || target.textContent)).trim();

      if (original !== current) {
        if (!modified_inputs.has(target)) {
          modified_inputs.add(target);
        }
      } else if (modified_inputs.has(target)) {
        modified_inputs.delete(target);
      }

      if(modified_inputs.size){
        const event = new Event('needSave')
        window.dispatchEvent(event);
      }
    });

    addEventListener(
      'saved',
      function(e) {
        modified_inputs.clear()
      },
      false
    );

    addEventListener('beforeunload', evt => {
      if (modified_inputs.size) {
        const unsaved_changes_warning = 'Changes you made may not be saved.';
        evt.returnValue = unsaved_changes_warning;
        return unsaved_changes_warning;
      }
    });

    const ua = navigator.userAgent.toLowerCase();

    if(/MicroMessenger/i.test(ua)) {
      let pushed = false

      addEventListener('needSave', evt => {
        if(!pushed) {
          pushHistory();

          window.addEventListener("popstate", function(e) {
            if(modified_inputs.size) {
              var cfi = confirm('确定要离开当前页面嘛?' + JSON.stringify(e));
              if (cfi) {
                modified_inputs.clear()
                history.go(-1)
              }else{
                e.preventDefault();
                e.stopPropagation();
              }
            }
          }, false);
        }

        pushed = true
      });
    }

    function pushHistory() {
      var state = {
        title: document.title,
        url: "#flag"
      };
      window.history.pushState(state, document.title, "#flag");
    }
  })();

0

Ich habe es anders gemacht und hier geteilt, damit jemand Hilfe bekommen kann, die nur mit Chrome getestet wurde.

Ich wollte den Benutzer vor dem Schließen der Registerkarte nur warnen, wenn es einige Änderungen gibt.

<input type="text" name="field" value="" class="onchange" />

var ischanged = false;

$('.onchange').change(function () {
    ischanged = true;
});

window.onbeforeunload = function (e) {
    if (ischanged) {
        return "Make sure to save all changes.";
    }        
};

Funktioniert gut, hat aber ein anderes Problem. Als ich das Formular abschicke, erhalte ich die unerwünschte Warnung. Ich habe viele Problemumgehungen gesehen. Dies liegt daran, dass beim Laden vor dem Laden vor dem Senden ein Brand ausgelöst onbeforeunload = nullwird Onclick-Ereignis der Senden-Schaltfläche wird vor diesen beiden Ereignissen ausgelöst, daher habe ich den Code aktualisiert

var isChanged = false;
var isSubmit = false;

window.onbeforeunload = function (e) {
    if (isChanged && (!isSubmit)) {
        return "Make sure to save all changes.";
    }        
};

$('#submitbutton').click(function () {
    isSubmit = true;
});

$('.onchange').change(function () {
    isChanged = true;
});

-5

Erstens haben die meisten Browser diese Funktion standardmäßig. Und warum brauchst du das überhaupt? Warum nicht das Formular synchron halten? Ich meine, speichern Sie es bei jeder Änderung, ohne auf die Übermittlung durch den Benutzer zu warten. Wie bei Google-Kontakten. Natürlich, wenn nur alle Felder in der Form obligatorisch sind. Benutzer mögen es nicht, wenn sie zwingen, etwas zu füllen, ohne die Möglichkeit zu haben, wegzugehen, um zu überlegen, ob sie es brauchen. :) :)


Haben Sie Recht, aber meine Formulare werden dynamisch generiert und die Felder sind nicht in meiner Kontrolle. Daher ist es für mich nicht möglich, alle Felder zu verfolgen und Anfragen über Ajax zu senden. Wenn Sie etwas im Sinn haben, teilen Sie es mir bitte mit.
Khan

Okay, es ist möglicherweise nicht für Ihre Zwecke erforderlich, kann aber dennoch implementiert werden. Wenn die Formularelemente auf dem Bildschirm angezeigt werden, können Sie Ihre eigenen Ereignishandler anhängen und die gewünschten Daten abrufen. Verwenden Sie dann AJAX, um die Daten an einem beliebigen Ort zu speichern. Selbst wenn die Formulare zufällig generierte IDs oder Klassennamen haben, können Sie XPaths verwenden, wenn Sie die Struktur des Formulars vorhersehen können. Es ist XML / HTML, oder? Sie könnten also sogar einen JAD mit den Verantwortlichen für das dynamisch generierte Formular haben und darüber sprechen, wie XSTL Ihnen beiden bei diesem Projekt zugute kommen könnte. Nur ein Gedanke ...
SimonDever

1
save it on any change without waiting any submitting from userSie wollen das nicht immer tun. Manchmal möchte der Benutzer viele Änderungen vornehmen und dann überprüfen und bestätigen, dass er sie speichern möchte.
BadHorsie

1
Ich habe nicht vorgeschlagen, das Formular einzureichen. Die Daten können in localStorage, in einem Cache oder sogar mit einem Entwurfsflag gespeichert werden. Es gibt viele Methoden für dieses Verhalten. Es ist viel besser, als den Benutzer darüber zu informieren, dass er das Formular nicht ausgefüllt hat. Wenn er das Fenster nicht schließt und schließt, muss er es beim nächsten Mal erneut ausfüllen. "Komm schon, Mann, sei nicht faul, dein Zug / Bus / Flugzeug / etc. Ist egal, und es ist uns egal, dass du ein Ladegerät von deinem Laptop vergessen hast, fülle einfach dieses verdammte Formular aus!"
YuS
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.