10 Stimmen

Erkennen, ob der Benutzer nach der Aufforderung onBeforeUnload geblieben ist

In einer Webanwendung, an der ich arbeite, erfasse ich onBeforeUnload, um den Benutzer zu fragen, ob er wirklich aussteigen möchte.

Wenn er sich entschließt, zu bleiben, gibt es eine Reihe von Dingen, die ich gerne tun würde. Was ich herauszufinden versuche, ist, dass er sich tatsächlich entschieden hat, zu bleiben.

Ich kann natürlich ein SetTimeout für "x" Sekunden deklarieren, und wenn das auslöst, dann würde es bedeuten, dass der Benutzer noch da ist (weil wir nicht entladen wurden). Das Problem ist, dass der Benutzer jede Zeit nehmen kann, um zu entscheiden, ob zu bleiben oder nicht...

Ich hatte zunächst gehofft, dass, während das Dialogfeld angezeigt wurde, SetTimeout Anrufe nicht auslösen würde, so dass ich eine Zeitüberschreitung für eine kurze Zeit festlegen könnte und es nur auslösen würde, wenn der Benutzer zu bleiben wählte. Allerdings, Zeitüberschreitungen tun auslösen, während der Dialog angezeigt wird, also funktioniert das nicht.

Eine andere Idee, die ich ausprobiert habe, ist das Erfassen von Mausbewegungen im Fenster/Dokument. Während der Dialog angezeigt wird, werden Mausbewegungen tatsächlich nicht ausgelöst, mit Ausnahme einer seltsamen Ausnahme, die wirklich auf meinen Fall zutrifft, also wird das auch nicht funktionieren.

Fällt jemandem eine andere Möglichkeit ein, dies zu tun?

Danke!


(Falls Sie neugierig sind, der Grund, warum das Erfassen von mouseMove nicht funktioniert, ist, dass ich einen IFrame in meiner Seite habe, der eine Website von einer anderen Domain enthält. Wenn zum Zeitpunkt des Entladens der Seite der Fokus innerhalb des IFrame ist, während das Dialogfeld angezeigt wird, dann bekomme ich das MouseMove-Ereignis, das EINMAL ausgelöst wird, wenn sich die Maus von innerhalb des IFrame nach außen bewegt (zumindest in Firefox). Das ist wahrscheinlich ein Fehler, aber trotzdem ist es sehr wahrscheinlich, dass das in unserem Fall passieren wird, also kann ich diese Methode nicht verwenden).

6voto

Daniel Magliola Punkte 29081

Am Ende habe ich mich in das Klick-Ereignis meines Dokuments eingeklinkt, und sobald ich einen Klick erhielt, ging ich davon aus, dass der Benutzer geblieben war.

Das ist keine gute Lösung, denn in den meisten Fällen (wenn man eine DiggBar hat) gibt es eine Menge falscher Negativmeldungen (die Leute sind geblieben und man merkt es nicht), aber in unserem Fall war es absolut sinnvoll, denn die Leute interagieren stark mit unserer Website, nicht nur mit den gerahmten Seiten.

Im Wesentlichen macht mein Code dies...

function OnBeforeUnload() {
    Event.observe(document, "click", UserStayed);
    if (IConsiderTheIFrameMightBeTryingToPopOut) {
        return "The site is trying to escape. Do you want to stay?";
    }
}

function UserStayed() {
Event.stopObserving(document, "click", UserStayed);
    // New we know the user is still with us for sure.
}

4voto

Kiefer Punkte 41

Ich habe diese Frage in den letzten Tagen im Internet recherchiert, und die Antwort lautet ausnahmslos "Nein". Man kann nicht mit Sicherheit sagen, ob ein Benutzer geblieben ist oder gegangen ist (abgesehen von der Tatsache, dass Ihre Anwendung nicht mehr funktioniert, wenn der Benutzer geht). Ich hasse "Nein"-Antworten. Ich habe mir das folgende Dienstprogramm ausgedacht.

var OnBeforeUnload = (function(){
    var
    FDUM = new Function,
    AFFIRM = function(){ return true; };

    var _reg = function(msg,opts){
        opts = opts || {};
        var
            pid = null,
            pre = typeof opts.prefire == 'function' ? opts.prefire : FDUM,
            callback = typeof opts.callback == 'function' ? opts.callback : FDUM,
            condition = typeof opts.condition == 'function' ? opts.condition : AFFIRM;

        window.onbeforeunload = function(){
            return condition() ? (pre(),setTimeout(function(){ pid = setTimeout(callback,20); },1),msg) : void 0; 
        }

        window.onunload = function(){ clearTimeout(pid); };

    }

    var _unreg = function(){ window.onbeforeunload = null;  }

    return {
        register : _reg,
        unregister : _unreg
    };

})();

So kann ein Aufruf wie

OnBeforeUnload.register('Hello!',{ 
    condition:function_that_returns_true_to_fire_event_false_to_ignore,
    prefire:function_to_call_on_page_exit_attempt, 
    callback:function_to_call_if_user_stays
});

Bedingung wird innerhalb des Handlers aufgerufen, um zu sehen, ob er aktiviert werden soll oder nicht. Ist dies der Fall, wird ein Prefire ausgeführt, bevor das Popup dem Benutzer angezeigt wird (Sie können ein Video anhalten), und der Callback erfolgt NUR, wenn der Benutzer bleibt.

Meine Logik war es, ein setTimeout in den Körper des Event-Handlers zu initiieren. Der setTimeout wird nicht ausgeführt, bis der Benutzer eine der Schaltflächen drückt. Danach wird er sofort ausgelöst. Der setTimeout ruft in diesem Fall nicht den Callback auf, sondern eine Proxy-Funktion, die einen weiteren Timeout für den Callback mit einer Verzögerung von 20ms ausführt. Wenn der Benutzer auf der Seite bleibt, wird der Callback ausgeführt. Wenn nicht, dann wird ein anderer Handler an onunload angehängt, der den Timeout löscht, der den Callback aufruft, wodurch sichergestellt wird, dass der Callback nie aufgerufen wird. Ich hatte bisher nur die Gelegenheit, es in Firefox, IE und Chrome zu testen, aber es hat bisher in allen drei Versionen ohne Probleme funktioniert.

Ich hoffe, dass dies den Leuten hilft, die genauso frustriert sind, wie ich es war, weil diese Frage von allen mit "Nein" beantwortet wurde. Dieser Code mag nicht perfekt sein, aber ich denke, er ist auf dem richtigen Weg.

0voto

Seph Reed Punkte 6186

Dies ist der Top-Treffer für diese Art von Frage, und ich weiß, dass der spezielle Fall (von vor 8 Jahren) konnte diese Lösung nicht verwenden, weil es in einem iFrame war, aber alle zukünftigen Comers wird wahrscheinlich mehr von der Antwort unten als die oben geholfen werden:

Sie können leicht sagen, wenn sie mit einem Körper-Ereignis-Listener geblieben sind, ich denke, mousemove und keydown kombiniert sollte genug sein.

Um festzustellen, ob sie gegangen sind, benötigen Sie einige serverseitige Funktionen.

Alles in allem wird es ungefähr so aussehen (Sie müssen die Ajax-Aufrufe an den Server selbst eingeben):

window.addEventListener("beforeunload", function(event){
    //tell your server they are attempting to leave
    var tryLeaveID = serverLogAttempToLeave();

    //an element with giant letters and warning text, because you can no longer set text on the alert box
    var unsavedWarning = document.getElementById("unsavedChangesWarning");
    unsavedWarning.style.display = "block";

    var onStay = function() {
        //if they stay, tell your server so
        serverRevokeAttemptToLeave(tryLeaveID);
        unsavedWarning.style.display = "none";
        document.body.removeEventListener("mousemove", onStay);
        document.body.removeEventListener("keydown", onStay);
    }

    document.body.addEventListener("mousemove", onStay);
    document.body.addEventListener("keydown", onStay);

    var dialogText =  "undisplayed text";
    event.returnValue = dialogText;
    return dialogText;
});

Auf der Serverseite müssen Sie etwas Unschönes verwenden, einen Timer. Machen Sie einen Stapel von Versuchen zu verlassen, und entfernen Sie sie entweder als angefordert auf bleiben, oder nach einer Minute oder so als eine bestätigte verlassen. Ich kann mir keinen Fall vorstellen, in dem die Feststellung, ob der Benutzer gegangen ist, zeitkritischer ist als ein paar Minuten, aber wenn Sie einen haben, kommentieren Sie ihn bitte, denn ich würde gerne darüber nachdenken.

-7voto

Chad Birch Punkte 70946

Warum verwenden Sie nicht einfach die Methode von StackOverflow, bei der Sie ein Popup-Fenster erhalten, in dem Sie die Auswahl treffen können:

Sind Sie sicher, dass Sie diese Seite verlassen wollen?

Sie haben mit dem Schreiben oder Bearbeiten eines Beitrags begonnen.

Drücken Sie OK, um fortzufahren, oder Abbrechen, um auf der aktuellen Seite zu bleiben.

Dann spielt es keine Rolle, wie lange sie brauchen. Wenn sie auf eine Schaltfläche klicken, gehen sie. Wenn sie auf die andere klicken, bleiben sie.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X