2009-05-04 7 views
9

In una web app su cui sto lavorando, sto cattura onbeforeunload per chiedere all'utente se ha davvero vuole uscire.Rilevare se l'utente rimasto dopo aver chiesto onbeforeunload

Ora, se decide di restare, ci sono un certo numero di cose che mi piacerebbe fare. Quello che sto cercando di capire è che in realtà ha scelto di rimanere.

Posso ovviamente dichiarare un SetTimeout per "x" secondi, e se ciò si attiva, significherebbe che l'utente è ancora lì (perché non siamo stati scaricati). Il problema è che l'utente può prendere qualsiasi momento per decidere se rimanere o meno ...

Inizialmente speravo che durante la finestra di dialogo, le chiamate di SetTimeout non si attivassero, quindi potrei impostare un timeout per un breve tempo e sarebbe sparato solo se l'utente ha scelto di rimanere. Tuttavia, i timeout do si attivano mentre viene visualizzata la finestra di dialogo, in modo che non funzioni.

Un'altra idea che ho provato è catturare mouseMoves sulla finestra/documento. Mentre viene mostrata la finestra di dialogo, mouseMoves infatti non sparare, tranne per una strana eccezione che si applica davvero al mio caso, in modo che non funzionerà neanche.

Qualcuno può pensare ad altro modo per farlo?

Grazie!


(Nel caso foste curiosi, la ragione per la cattura mouseMove non funziona è che ho un IFrame nella mia pagina, contenente un sito da un altro dominio. Se al momento dello scarico della pagina, il la messa a fuoco è all'interno dell'IFrame, mentre la finestra di dialogo mostra, quindi viene attivato l'evento MouseMove ONCE quando il mouse si sposta dall'IFrame all'esterno (almeno in Firefox). Probabilmente è un bug, ma è comunque probabile che sia " Succederemo nel nostro caso, quindi non posso usare questo metodo).

risposta

6

Quello che ho finito per fare è stato agganciare all'evento click per il mio documento, e una volta ricevuto un clic ho considerato che l'utente era rimasto.

Non è una buona soluzione, nella maggior parte dei casi (se sei un DiggBar) avrai molti falsi negativi (le persone rimarranno e non lo saprai mai), ma nel nostro caso ha perfettamente senso , perché le persone interagiscono pesantemente con il nostro sito, non solo con i siti incorniciati.

Esenzialmente, il mio codice lo fa ...

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

Signore, sono il mio eroe. – Pascal

+0

Felice di aver aiutato? Il codice –

+0

va bene. Voglio eseguire la funzione logout() se l'utente fa clic sul pulsante "Lascia questa pagina". Ma come posso rilevare se l'utente ha fatto clic su "Abbandona questa pagina" oppure no? –

-7

perché non utilizzare il metodo che StackOverflow fa, in cui si ottiene una finestra di pop-up che consente di effettuare la scelta:

Sei sicuro di voler navigare lontano da questa pagina?

Hai iniziato a scrivere o modificare un post.

Premere OK per continuare o Annulla per rimanere nella pagina corrente

Poi non importa quanto tempo impiegano. Se fanno clic su un pulsante, se ne vanno. Se fanno clic sull'altro, rimangono.

+0

Lo sto facendo. Ma voglio fare qualcosa una volta che sono rimasti, SOLO SE sono rimasti. In pratica sto facendo sapere al server che sono rimasti, il che significa che lo scaricamento è stato causato da qualcosa che sta cercando di uscire da un IFrame e non da loro che chiudono la finestra. Questo mi consente di registrare possibili cause per lo scaricamento, di cui posso fare più tardi. Ma voglio solo farlo SE sono rimasti, voglio essere sicuro che siano rimasti prima di notificare il server. –

+0

Quindi utilizzare il pulsante "I want to stay" nel popup per attivare l'esecuzione delle "cose". Forse non sto capendo il problema. –

+1

Hmmm, il pulsante "Voglio rimanere" appartiene al browser, non a me. Non posso toccarlo o fare qualcosa, è una finestra standard con cui non riesco a interagire. E per quanto ne so, non vi è alcun evento specifico nella finestra/documento che si innesca quando l'utente decide di rimanere. –

3

Ho fatto ricerche questa domanda on-line per i giorni scorsi e la risposta, invariabilmente, è "no", non si può dire, di sicuro, che un utente rimasto oa sinistra (a parte il fatto che il vostro l'app smette di funzionare se l'utente esce). Odio le risposte "no". Ho trovato la seguente utilità.

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

})(); 

Quindi, una chiamata come ad esempio

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

condizione sarà chiamato all'interno del gestore per vedere se deve attivare o meno. In tal caso, il prefire viene eseguito prima che il popup venga mostrato all'utente (potrebbe essere necessario mettere in pausa un video) e la richiamata avverrà SOLO se l'utente rimane.

La mia logica era di avviare un setTimeout nel corpo del gestore eventi. Il setTimeout non verrà eseguito finché l'utente non preme uno dei pulsanti. Dopo che lo fanno, si spara immediatamente. In questo caso, setTimeout non chiama la richiamata, ma una funzione proxy che esegue un altro timeout per la richiamata con un ritardo di 20ms. Se l'utente rimane sulla pagina, la callback viene eseguita. In caso contrario, un altro gestore viene collegato a onunload che cancella il timeout che chiamerà la richiamata, assicurando che la richiamata non venga mai chiamata. Ho avuto solo la possibilità di controllarlo in Firefox, IE e Chrome, ma ha funzionato finora in tutte e tre le cose senza intoppi.

Spero che questo aiuti le persone frustrate quanto me dal brevetto "no" dato universalmente a questa domanda. Questo codice potrebbe non essere perfetto, ma penso che sia sulla strada giusta.

+0

Questo ha funzionato solo se ho impostato il timeout su diversi secondi. Altrimenti, quando l'utente fa clic sul pulsante per uscire dalla pagina, viene ancora chiamato il "callback" (function_to_call_if_user_stays). Nel mio caso, questo è dovuto al fatto che il collegamento richiesto che ha attivato onbeforeunload() richiede diversi secondi per tornare dal server, quindi onunload() non viene chiamato per alcuni secondi. – CyberMonk

0

Questo è il top hit per questo tipo di domanda, e so che il caso specifico (di 8 anni fa) non è stato possibile utilizzare questa soluzione perché era in un iFrame, ma qualsiasi futuro sarà probabilmente più aiutato da la risposta al di sotto di quelli di cui sopra:

Si può facilmente dire se sono stati con un listener di eventi corpo, penso MouseMove e KeyDown combinato dovrebbe essere sufficiente.

Per sapere se se ne sono andati, è necessario un po 'di roba lato server.

Tutto sommato, sembrerà qualcosa di simile (Dovrete riempire le chiamate AJAX al server da soli):

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

Sul lato server, si sta andando ad avere usare qualcosa di brutto, un timer. Fai una serie di tentativi di andarsene e rimuoverli come richiesto sul soggiorno o dopo un minuto o più come un congedo confermato. Non riesco a immaginare alcun caso in cui sapere se l'utente ha lasciato è più sensibile al fattore tempo di alcuni minuti, ma se ne hai uno, per favore commenta perché mi piacerebbe pensarci.

Problemi correlati