Best way to detect when a user leaves a web page?

前端 未结 8 2157
太阳男子
太阳男子 2020-11-22 01:57

What is the best way to detect if a user leaves a web page?

The onunload JavaScript event doesn\'t work every time (the HTTP request takes longer than t

相关标签:
8条回答
  • 2020-11-22 02:08

    Try the onbeforeunload event: It is fired just before the page is unloaded. It also allows you to ask back if the user really wants to leave. See the demo onbeforeunload Demo.

    Alternatively, you can send out an Ajax request when he leaves.

    0 讨论(0)
  • 2020-11-22 02:13

    For What its worth, this is what I did and maybe it can help others even though the article is old.

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

    Ajax call to 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);
            }
        }
    }
    

    Database:

    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;
    

    Basically every 5 seconds the js will post to a php file that will track the user and the users ip address. Active users are simply a database record that have an update to the database time stamp within 5 seconds. Old users stop updating to the database. The ip address is used just to ensure that a user is unique so 2 people on the site at the same time don't register as 1 user.

    Probably not the most efficient solution but it does the job.

    0 讨论(0)
  • 2020-11-22 02:15

    Thanks to Service Workers, it is possible to implement a solution similar to Adam's purely on the client-side, granted the browser supports it. Just circumvent heartbeat requests:

    // 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')
        )
      }
    })
    
    0 讨论(0)
  • 2020-11-22 02:15

    In the case you need to do some asynchronous code (like sending a message to the server that the user is not focused on your page right now), the event beforeunload will not give time to the async code to run. In the case of async I found that the visibilitychange and mouseleave events are the best options. These events fire when the user change tab, or hiding the browser, or taking the courser out of the window scope.

    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 讨论(0)
  • 2020-11-22 02:16

    Mozilla Developer Network has a nice description and example of onbeforeunload.

    If you want to warn the user before leaving the page if your page is dirty (i.e. if user has entered some data):

    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
    });
    
    0 讨论(0)
  • 2020-11-22 02:22

    Here's an alternative solution - since in most browsers the navigation controls (the nav bar, tabs, etc.) are located above the page content area, you can detect the mouse pointer leaving the page via the top and display a "before you leave" dialog. It's completely unobtrusive and it allows you to interact with the user before they actually perform the action to leave.

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

    The downside is that of course it's a guess that the user actually intends to leave, but in the vast majority of cases it's correct.

    0 讨论(0)
提交回复
热议问题