Il modo migliore per rilevare quando un utente lascia una pagina Web?


195

Qual è il modo migliore per rilevare se un utente lascia una pagina Web?

L' onunloadevento JavaScript non funziona ogni volta (la richiesta HTTP richiede più tempo del tempo necessario per chiudere il browser).

La creazione di uno sarà probabilmente bloccata dagli attuali browser.

Risposte:


219

Prova l' onbeforeunloadevento: viene generato appena prima che la pagina venga scaricata. Ti permette anche di chiedere se l'utente vuole davvero andarsene. Guarda la demo prima di scaricare Demo .

In alternativa, puoi inviare una richiesta Ajax quando lascia.


3
Sarebbe bello se l'utente monitorasse se il modulo fosse cambiato e chiedesse solo se lo faceva - quindi non è fastidioso.
adam0101,

3
Si noti inoltre che vari browser mobili ignorano il risultato dell'evento (ovvero, non chiedono conferma all'utente). Firefox ha una preferenza nascosta in about: config per fare lo stesso. In sostanza, ciò significa che l'utente conferma sempre che il documento può essere scaricato.
MJB,

2
Si noti che questo metodo evoca anche quando l'utente aggiorna la pagina o invia un modulo.
Zaytsev Dmitry,

@Andreas Petersson, ho la stessa sfida con l'obiettivo di abbandonare la sessione utente. Come posso acquisire l'URL digitato per verificare se appartiene al progetto?
Jcc.Sanabria,

21

Mozilla Developer Network ha una bella descrizione ed esempio di onbeforeunload .

Se vuoi avvisare l'utente prima di lasciare la pagina se la tua pagina è sporca (ovvero se l'utente ha inserito alcuni dati):

window.addEventListener('beforeunload', function(e) {
  var myPageIsDirty = ...; //you implement this logic...
  if(myPageIsDirty) {
    //following two lines will cause the browser to ask the user if they
    //want to leave. The text of this dialog is controlled by the browser.
    e.preventDefault(); //per the standard
    e.returnValue = ''; //required for Chrome
  }
  //else: user is allowed to leave without a warning dialog
});

10

Ecco una soluzione alternativa: poiché nella maggior parte dei browser i controlli di navigazione (barra di navigazione, schede, ecc.) Si trovano sopra l'area del contenuto della pagina, puoi rilevare il puntatore del mouse che lascia la pagina in alto e visualizzare un " prima di uscire " dialogo. È completamente discreto e ti consente di interagire con l'utente prima che eseguano effettivamente l'azione per uscire.

$(document).bind("mouseleave", function(e) {
    if (e.pageY - $(window).scrollTop() <= 1) {    
        $('#BeforeYouLeaveDiv').show();
    }
});

Il rovescio della medaglia è che ovviamente si tratta di un'ipotesi che l'utente intende effettivamente lasciare, ma nella stragrande maggioranza dei casi è corretto.


sto cercando qualcosa di simile, voglio mostrare qualcosa di discreto al mio utente, prima di lasciare la mia pagina, sto cercando qualcosa di simile a un evento hover sul pulsante indietro, perché ho bisogno di lanciare l'evento prima che l'utente faccia clic per tornare indietro. Credo che il modo migliore sia davvero quello di rilevare il documento del congedo del mouse e fare una logica per determinare se l'utente ha interagito con la pagina.
Leonardo Souza Paiva,

8

Per questo sto usando:

window.onbeforeunload = function (e) {

}

Viene generato appena prima che la pagina venga scaricata.


1
Opera 12 e versioni precedenti non supportano questo ... zachleat.com/web/…
Cyrus,

In che modo è meglio delle due precedenti risposte che offrono la stessa soluzione onbeforeunload?
Dan Dascalescu

5

So che a questa domanda è stata data una risposta, ma nel caso in cui si desideri attivare qualcosa solo quando il BROWSER effettivo è chiuso e non solo quando si verifica un pageload, è possibile utilizzare questo codice:

window.onbeforeunload = function (e) {
        if ((window.event.clientY < 0)) {
            //window.localStorage.clear();
            //alert("Y coords: " + window.event.clientY)
        }
};

Nel mio esempio, sto cancellando l'archiviazione locale e avvisando l'utente con i mouse y coords, solo quando il browser è chiuso, questo verrà ignorato su tutti i caricamenti di pagine dall'interno del programma.


window.event non è definito per me
Karl Glaser

L'esempio di Merr Leader è sbagliato, window.event dovrebbe essere usato solo come fallback, ad esempio per le versioni precedenti di IE, in altri casi, edovrebbe essere usato il parametro evento (la variabile in questo caso): stackoverflow.com/questions/9813445/ …
Sk8erPeter

Non arriverei al punto di dire che mi sbaglio. I miei esempi funzionano per me in IE e Chrome bene. Il mio esempio è stato per lo scenario in cui l'utente fa clic sulla X (chiudi) sul browser web. Né il modo più carino forse, ma funziona.
Merr Leader

Da MDN: This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. developer.mozilla.org/en-US/docs/Web/API/Window/event
Robin Neal

3

Un modo (leggermente confuso) per farlo è la sostituzione e i collegamenti che portano via dal tuo sito con una chiamata AJAX sul lato server, indicando che l'utente sta uscendo, quindi usa lo stesso blocco javascript per portarlo sul sito esterno che ha ho richiesto.

Ovviamente questo non funzionerà se l'utente semplicemente chiude la finestra del browser o digita un nuovo URL.

Per ovviare a questo, dovresti potenzialmente utilizzare il setTimeout () di Javascript sulla pagina, effettuare una chiamata AJAX ogni pochi secondi (a seconda di quanto velocemente vuoi sapere se l'utente è partito).


4
Se si utilizza l'approccio home report, non è necessario modificare tutti i collegamenti nella pagina.
Vinko Vrsalovic,

3

Grazie a Service Workers , è possibile implementare una soluzione simile a quella di Adam esclusivamente sul lato client, a condizione che il browser la supporti. Basta eludere le richieste di battito cardiaco:

// The delay should be longer than the heartbeat by a significant enough amount that there won't be false positives
const liveTimeoutDelay = 10000
let liveTimeout = null

global.self.addEventListener('fetch', event => {
  clearTimeout(liveTimeout)
  liveTimeout = setTimeout(() => {
    console.log('User left page')
    // handle page leave
  }, liveTimeoutDelay)
  // Forward any events except for hearbeat events
  if (event.request.url.endsWith('/heartbeat')) {
    event.respondWith(
      new global.Response('Still here')
    )
  }
})

Volevi dire che da qualche parte nel codice client, ci deve essere un setInterval(() => fetch('/heartbeat'), 5000)?
Dan Dascalescu

@DanDascalescu Corretto. Il codice JS invia una richiesta di rete a / heartbeat e il tecnico dell'assistenza la intercetta.
Jeffrey Sweeney,

2

Nel caso in cui sia necessario eseguire un codice asincrono (come l'invio di un messaggio al server che l'utente non è focalizzato sulla propria pagina in questo momento), l'evento beforeunloadnon darà il tempo per l'esecuzione del codice asincrono. Nel caso di asincrono ho scoperto che gli eventi visibilitychangee mouseleavesono le migliori opzioni. Questi eventi si attivano quando l'utente cambia scheda o nasconde il browser o estrae il cursore dall'ambito della finestra.

document.addEventListener('mouseleave', e=>{
     //do some async code
})

document.addEventListener('visibilitychange', e=>{
     if (document.visibilityState === 'visible') {
   //report that user is in focus
    } else {
     //report that user is out of focus
    }  
})


0

Per quello che vale, questo è quello che ho fatto e forse può aiutare gli altri anche se l'articolo è vecchio.

PHP:

session_start();

$_SESSION['ipaddress'] = $_SERVER['REMOTE_ADDR'];

if(isset($_SESSION['userID'])){
    if(!strpos($_SESSION['activeID'], '-')){
        $_SESSION['activeID'] = $_SESSION['userID'].'-'.$_SESSION['activeID'];
    }
}elseif(!isset($_SESSION['activeID'])){
    $_SESSION['activeID'] = time();
}

JS

window.setInterval(function(){
            var userid = '<?php echo $_SESSION['activeID']; ?>';
            var ipaddress = '<?php echo $_SESSION['ipaddress']; ?>';
            var action = 'data';

            $.ajax({
                url:'activeUser.php',
                method:'POST',
                data:{action:action,userid:userid,ipaddress:ipaddress},
                success:function(response){
                     //alert(response);                 
                }
            });
          }, 5000);

Chiamata Ajax a activeUser.php

if(isset($_POST['action'])){
    if(isset($_POST['userid'])){
        $stamp = time();
        $activeid = $_POST['userid'];
        $ip = $_POST['ipaddress'];

        $query = "SELECT stamp FROM activeusers WHERE activeid = '".$activeid."' LIMIT 1";
        $results = RUNSIMPLEDB($query);

        if($results->num_rows > 0){
            $query = "UPDATE activeusers SET stamp = '$stamp' WHERE activeid = '".$activeid."' AND ip = '$ip' LIMIT 1";
            RUNSIMPLEDB($query);
        }else{
            $query = "INSERT INTO activeusers (activeid,stamp,ip)
                    VALUES ('".$activeid."','$stamp','$ip')";
            RUNSIMPLEDB($query);
        }
    }
}

Banca dati:

CREATE TABLE `activeusers` (
  `id` int(11) NOT NULL,
  `activeid` varchar(20) NOT NULL,
  `stamp` int(11) NOT NULL,
  `ip` text
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Praticamente ogni 5 secondi js invierà un file php che traccia l'utente e l'indirizzo IP dell'utente. Gli utenti attivi sono semplicemente un record di database che ha un aggiornamento al timestamp del database entro 5 secondi. I vecchi utenti interrompono l'aggiornamento al database. L'indirizzo IP viene utilizzato solo per garantire che un utente sia univoco, quindi 2 persone sul sito contemporaneamente non si registrano come 1 utente.

Probabilmente non è la soluzione più efficiente ma fa il lavoro.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.