Détecter si l'utilisateur est resté après avoir invité onBeforeUnload

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

Maintenant, s'il décide de rester, il y a plusieurs choses que je voudrais faire. Ce que j'essaie de comprendre, c'est qu'il a choisi de rester.

Je peux bien sûr déclarer SetTimeout pour "x" secondes, et si cela se produit, cela signifie que l'utilisateur est toujours là (car nous n'avons pas été déchargés). Le problème est que l'utilisateur peut prendre le temps de décider de rester ou non …

J'espérais d'abord que pendant que le dialogue était en train de s'afficher, les appels de SetTimeout ne déclencheraient pas, alors je pourrais régler un délai d'attente pour une courte période et il ne prendrait que le feu si l'utilisateur choisissait de rester. Cependant, les délais d'attente s'allument lorsque la boîte de dialogue s'affiche, ce qui ne fonctionne pas.

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

Quelqu'un peut-il penser à autre chose?

Merci!


(Si vous êtes curieux, la raison pour laquelle la capture de mouseMove ne fonctionne pas, c'est que j'ai un IFrame dans ma page, contenant un site d'un autre domaine. Si au moment du déchargement de la page, l'accent est mis sur IFrame, alors que La boîte de dialogue s'affiche, puis je reçois l'événement MouseMove déclenchant une fois que la souris passe de l'intérieur de l'IFrame à l'extérieur (au moins dans Firefox). C'est probablement un bug, mais il est très probable que cela se produise dans notre cas, alors Je ne peux pas utiliser cette méthode).

Ce que j'ai fini de faire était d'accrocher dans l'événement de clic pour mon document, et une fois 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 fausses négatives (les gens seront restés et vous ne le saurez jamais), mais dans notre cas, c'était vraiment logique, car les gens interagissent Fortement avec notre site, non seulement avec les sites encadrés.

Esprit, mon code le fait …

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

Je faisais une recherche sur cette question en ligne ces derniers jours et la réponse est invariablement «non», vous ne pouvez pas dire, à coup sûr, qu'un utilisateur est resté ou laissé (autrement que le fait que votre application quitte son travail si l'utilisateur quitte ). Je déteste les réponses «non». J'ai trouvé l'utilité suivante.

 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, préfire est exécuté avant que le popup ne s'affiche à l'utilisateur (vous voudrez peut-être mettre une vidéo en pause) et le rappel se produira SEULEMENT si l'utilisateur reste.

Ma logique était de lancer un setTimeout dans le corps du gestionnaire d'événements. Le setTimeout ne s'effectuera pas jusqu'à ce que l'utilisateur appuie sur l'un des boutons. Après cela, il s'enflamme immédiatement. SetTimeout dans ce cas 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 est exécuté. Si ce n'est pas le cas, un autre gestionnaire est attaché à une surcharge qui efface le délai d'attente qui appellera le 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 il a fonctionné jusqu'ici dans les trois sans hoquet.

J'espère que cela aide les gens aussi frustrés que par le brevet «non» donné universellement à cette question. Ce code peut ne pas être parfait, mais je pense que c'est sur la bonne voie.

C'est le meilleur succès pour ce type de question, et je sais que le cas spécifique (il y a 8 ans) n'a pas pu utiliser cette solution car il s'agissait d'un iFrame, mais les futurs gagnants seront probablement mieux aidés par la réponse ci-dessous Ci-dessus:

Vous pouvez facilement dire s'ils ont séjourné avec un auditeur d'événement corporel, je pense que mousemove et le raccourci combiné devraient suffire.

Pour dire si elles sont partis, vous aurez besoin de certaines choses côté serveur.

Dans l'ensemble, il ressemblera à quelque chose comme ça (vous devrez remplir les appels ajax sur le serveur vous-même):

 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 devrez utiliser quelque chose de laid, une minuterie. Faites une pile de tentatives de départ, et supprimez-les soit comme demandé sur le séjour, soit après une minute ou deux comme un congé confirmé. Je ne peux imaginer aucun cas où savoir si l'utilisateur a quitté est plus sensible au temps que quelques minutes, mais si vous en avez un, veuillez commenter parce que j'aimerais y réfléchir.

Pourquoi ne pas utiliser la méthode utilisée par StackOverflow, où vous obtenez une boîte contextuelle qui vous permet de choisir:

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

Vous avez commencé à écrire ou à éditer une publication.

Appuyez sur OK pour continuer, ou sur Annuler pour rester sur la page actuelle

Ensuite, peu importe la durée qu'ils prennent. S'ils cliquent sur un bouton, ils partent. S'ils cliquent sur l'autre, ils restent.