La meilleure façon de détecter quand un utilisateur quitte une page Web?


195

Quelle est la meilleure façon de détecter si un utilisateur quitte une page Web?

L' onunloadévénement JavaScript ne fonctionne pas à chaque fois (la demande HTTP prend plus de temps que le temps requis pour fermer le navigateur).

En créer un sera probablement bloqué par les navigateurs actuels.

Réponses:


219

Essayez l' onbeforeunloadévénement: il est déclenché juste avant le déchargement de la page. Il vous permet également de demander en retour si l'utilisateur veut vraiment partir. Voir la démo onbeforeunload Demo .

Alternativement, vous pouvez envoyer une demande Ajax à son départ.


3
Ce serait bien pour l'utilisateur si vous suiviez si le formulaire avait changé et ne demandiez que si c'était le cas - ce n'est donc pas ennuyeux.
adam0101

3
Notez également que divers navigateurs mobiles ignorent le résultat de l'événement (c'est-à-dire qu'ils ne demandent pas de confirmation à l'utilisateur). Firefox a une préférence cachée dans about: config pour faire de même. En substance, cela signifie que l'utilisateur confirme toujours que le document peut être déchargé.
MJB

2
Notez que cette méthode évoque également lorsque l'utilisateur actualise la page ou soumet un formulaire.
Zaytsev Dmitry

@Andreas Petersson, j'ai le même défi avec l'objectif de supprimer la session utilisateur. Comment puis-je capturer l'URL tapée pour vérifier si elle appartient au projet?
Jcc.Sanabria

21

Mozilla Developer Network a une belle description et un exemple de onbeforeunload .

Si vous souhaitez avertir l'utilisateur avant de quitter la page si votre page est sale (c'est-à-dire si l'utilisateur a entré des données):

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

Voici une solution alternative - puisque dans la plupart des navigateurs, les commandes de navigation (la barre de navigation, les onglets, etc.) sont situées au - dessus de la zone de contenu de la page, vous pouvez détecter le pointeur de la souris quittant la page par le haut et afficher un " avant de partir ". dialogue. C'est complètement discret et cela vous permet d'interagir avec l'utilisateur avant qu'il n'effectue réellement l'action de quitter.

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

L'inconvénient est que, bien sûr, c'est une supposition que l'utilisateur a réellement l'intention de partir, mais dans la grande majorité des cas, c'est correct.


je regarde quelque chose comme, je veux montrer quelque chose d'intrus à mon utilisateur, avant de quitter ma page, je regarde quelque chose comme un événement survolé sur le bouton de retour, parce que je dois déclencher l'événement avant que l'utilisateur clique pour revenir. Je crois que le meilleur moyen est vraiment de détecter le document de sortie du corps de la souris et de faire une logique pour déterminer si l'utilisateur a interagi avec la page.
Leonardo Souza Paiva

8

Pour cela, j'utilise:

window.onbeforeunload = function (e) {

}

Il est déclenché juste avant le déchargement de la page.


1
Opera 12 et les versions antérieures ne prennent pas en charge cela ... zachleat.com/web/…
Cyrus

Comment est-ce mieux que les deux réponses précédentes qui donnent la même solution onbeforeunload,?
Dan Dascalescu

5

Je sais que cette question a été répondue, mais si vous souhaitez que quelque chose se déclenche uniquement lorsque le NAVIGATEUR est fermé, et pas seulement lorsqu'un chargement de page se produit, vous pouvez utiliser ce code:

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

Dans mon exemple, j'efface le stockage local et alerte l'utilisateur avec les souris et les cordons, uniquement lorsque le navigateur est fermé, cela sera ignoré lors de tous les chargements de page depuis le programme.


window.event n'est pas défini pour moi
Karl Glaser

L'exemple de Merr Leader est erroné, window.event ne doit être utilisé que comme solution de rechange, par exemple pour les anciennes versions d'IE, dans d'autres cas, le paramètre d'événement (la evariable dans ce cas) doit être utilisé: stackoverflow.com/questions/9813445/ …
Sk8erPeter

Je n'irais pas jusqu'à dire que je me trompe. Mes exemples fonctionnent très bien pour moi dans IE et Chrome. Mon exemple était pour le scénario où l'utilisateur clique sur le X (fermer) sur le navigateur Web. Ni la plus jolie façon peut-être, mais ça marche.
Merr Leader

De 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

Une façon (légèrement hacky) de le faire est de remplacer et de créer des liens qui mènent loin de votre site avec un appel AJAX vers le serveur, indiquant que l'utilisateur quitte, puis utilisez ce même bloc javascript pour amener l'utilisateur vers le site externe qu'ils 'ai demandé.

Bien sûr, cela ne fonctionnera pas si l'utilisateur ferme simplement la fenêtre du navigateur ou saisit une nouvelle URL.

Pour contourner cela, vous devrez peut-être utiliser setTimeout () de Javascript sur la page, en effectuant un appel AJAX toutes les quelques secondes (selon la vitesse à laquelle vous souhaitez savoir si l'utilisateur est parti).


4
Si vous utilisez l'approche du rapport d'accueil, il n'est pas nécessaire de modifier chaque lien de la page.
Vinko Vrsalovic

3

Grâce aux Service Workers , il est possible d'implémenter une solution similaire à celle d' Adam purement côté client, à condition que le navigateur le supporte. Contournez simplement les demandes de battement de cœur:

// 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')
    )
  }
})

Voulez-vous dire que quelque part dans le code client, il doit y avoir un setInterval(() => fetch('/heartbeat'), 5000)?
Dan Dascalescu

@DanDascalescu Correct. Le code JS envoie une requête réseau à / heartbeat et le technicien de service l'intercepte.
Jeffrey Sweeney

2

Dans le cas où vous devez faire du code asynchrone (comme envoyer un message au serveur que l'utilisateur n'est pas concentré sur votre page en ce moment), l'événement beforeunloadne donnera pas le temps au code asynchrone de s'exécuter. Dans le cas de l'async, j'ai trouvé que les événements visibilitychangeet mouseleavesont les meilleures options. Ces événements se déclenchent lorsque l'utilisateur change d'onglet, ou masque le navigateur, ou sort le coursier de la portée de la fenêtre.

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

Pour ce que ça vaut, c'est ce que j'ai fait et peut-être que cela peut aider les autres même si l'article est ancien.

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

Appel Ajax à 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);
        }
    }
}

Base de données:

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;

Fondamentalement, toutes les 5 secondes, le js publiera dans un fichier php qui suivra l'utilisateur et l'adresse IP des utilisateurs. Les utilisateurs actifs sont simplement un enregistrement de base de données qui a une mise à jour de l'horodatage de la base de données dans les 5 secondes. Les anciens utilisateurs arrêtent la mise à jour de la base de données. L'adresse IP est utilisée uniquement pour garantir qu'un utilisateur est unique afin que 2 personnes sur le site en même temps ne s'enregistrent pas comme 1 utilisateur.

Probablement pas la solution la plus efficace mais elle fait l'affaire.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.