Question

Dans une application Web sur laquelle je travaille, je saisis onBeforeUnload pour demander à l'utilisateur s'il veut vraiment quitter.

Maintenant, s’il décide de rester, il y a un certain nombre de choses que j'aimerais faire. Ce que j'essaie de comprendre, c'est qu'il a effectivement choisi de rester.

Je peux bien sûr déclarer un SetTimeout pour " x " secondes, et si cela se déclenche, alors cela signifierait que l'utilisateur est toujours là (parce que nous n'avons pas été déchargés). Le problème est que l’utilisateur peut prendre tout moment pour décider de rester ou non ...

J'espérais d'abord que, pendant que la boîte de dialogue était affichée, les appels SetTimeout ne se déclenchaient pas, je pouvais donc définir un délai d'expiration et ne se déclencher que si l'utilisateur choisissait de rester. Toutefois, les délais ne sont activés tant que la boîte de dialogue est affichée. Cela ne fonctionne donc pas.

Une autre idée que j'ai essayée est de capturer mouseMoves sur la fenêtre / le document. Alors que la boîte de dialogue est affichée, mouseMoves ne se déclenche pas, à l'exception d'une exception étrange qui s'applique vraiment à mon cas, cela ne fonctionnera pas non plus.

Quelqu'un peut-il penser à une autre façon de faire cela?

Merci!

(Si vous êtes curieux, capturer mouseMove ne fonctionne pas, c'est que j'ai un IFrame dans ma page, qui contient un site provenant d'un autre domaine. Si au moment du déchargement de la page, le focus est placé dans le dossier. IFrame, pendant que la boîte de dialogue montre, puis je reçois l'événement MouseMove une fois lorsque la souris se déplace de l'intérieur de l'IFrame vers l'extérieur (du moins dans Firefox). C'est probablement un bogue, mais il est très probable cas, donc je ne peux pas utiliser cette méthode).

Était-ce utile?

La solution

Ce que j'ai fini par faire, c'est de m'accrocher à l'événement click pour mon document. Dès que j'ai reçu un clic, j'ai considéré que l'utilisateur était resté.

Ce n’est pas une bonne solution. Dans la plupart des cas (si vous êtes un DiggBar), vous aurez beaucoup de faux négatifs (les gens seront restés et vous ne le saurez jamais), mais dans notre cas, cela était parfaitement logique, parce que les gens interagissent beaucoup avec notre site, pas seulement avec les sites encadrés.

Essentiellement, mon code fait cela ...

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

Autres conseils

Je fais des recherches sur cette question en ligne depuis quelques jours et la réponse, invariablement, est "non". vous ne pouvez pas affirmer avec certitude qu'un utilisateur est resté ou est parti (à part le fait que votre application cesse de fonctionner si l'utilisateur le quitte). Je déteste " no " réponses. Je suis venu avec l'utilitaire suivant.

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

})();

Donc, un appel tel que

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

sera appelée dans le gestionnaire pour voir si elle doit être activée ou non. Si tel est le cas, prefire est exécuté avant que la fenêtre contextuelle ne s'affiche (vous pouvez mettre en pause une vidéo) et le rappel aura lieu UNIQUEMENT si l'utilisateur reste.

Ma logique était d'initier un setTimeout dans le corps du gestionnaire d'événements. SetTimeout ne sera exécuté que lorsque l'utilisateur appuiera sur l'un des boutons. Après cela, il se déclenche immédiatement. Dans ce cas, setTimeout n'appelle pas le rappel, mais une fonction proxy qui exécute un autre délai d'attente pour le rappel avec un délai de 20 ms. Si l'utilisateur reste sur la page, le rappel s'exécute. Si ce n'est pas le cas, un autre gestionnaire est associé à onunload, ce qui efface le délai d'expiration du rappel, en veillant à ce que le rappel ne soit jamais appelé. Je n'ai eu que la chance de le vérifier dans Firefox, IE et Chrome, mais cela a fonctionné jusqu'à présent dans les trois cas sans problème.

J'espère que cela aidera les gens aussi frustrés que le brevet "non". donné universellement à cette question. Ce code n'est peut-être pas parfait, mais je pense qu'il est sur la bonne voie.

C'est le top hit pour ce type de question, et je sais que le cas spécifique (il y a 8 ans) ne pourrait pas utiliser cette solution car elle se trouvait dans un iFrame, mais les futurs venus seront probablement plus aidés par la réponse ci-dessous à celle ci-dessus:

Vous pouvez facilement savoir s’ils sont restés avec un auditeur d’événement corporel, je pense que mousemove et keydown devraient suffire.

Pour savoir s’ils sont partis, vous allez avoir besoin de quelques outils côté serveur.

Dans l’ensemble, cela ressemblera à quelque chose comme ça (vous devrez remplir vous-même les appels ajax au serveur):

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

Du côté du serveur, vous allez devoir utiliser quelque chose de laid, une minuterie. Faites une pile de tentatives pour partir et retirez-les, soit comme demandé lors du séjour, soit après une minute environ de congé confirmé. Je ne peux pas imaginer de cas où savoir si l'utilisateur est parti est plus sensible au temps que quelques minutes, mais si vous en avez une, merci de la commenter, car j'aimerais bien y réfléchir.

Pourquoi ne pas utiliser simplement la méthode utilisée par StackOverflow, dans laquelle vous obtenez une boîte de dialogue vous permettant de choisir:

  

Êtes-vous sûr de vouloir quitter cette page?

     

Vous avez commencé à écrire ou à modifier un message.

     

Appuyez sur OK pour continuer ou sur Annuler pour rester sur la page en cours

Ensuite, peu importe combien de temps ils prennent. S'ils cliquent sur un bouton, ils partent. S'ils cliquent sur l'autre, ils restent.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top