Лучший способ определить, когда пользователь покидает веб-страницу?

Как лучше всего определить, покидает ли пользователь веб-страницу?

onunload Событие JavaScript не работает каждый раз (запрос HTTP занимает больше времени, чем требуется для завершения работы браузера).

Возможно, его создание будет заблокировано текущими браузерами.

12 ответов

Решение

Попробуйте onbeforeunload Событие: оно запускается перед тем, как страница выгружается. Это также позволяет вам спросить, действительно ли пользователь хочет уйти. Посмотрите демо на сайте до загрузки.

Кроме того, вы можете отправить запрос Ajax, когда он уходит.

У Mozilla Developer Network есть хорошее описание и пример onbeforeunload.

Если вы хотите предупредить пользователя перед тем, как покинуть страницу, если ваша страница грязная (т.е. если пользователь ввел некоторые данные):

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

Вот альтернативное решение - поскольку в большинстве браузеров элементы навигации (панель навигации, вкладки и т. Д.) Расположены над областью содержимого страницы, вы можете обнаружить указатель мыши, покидающий страницу через верхнюю часть, и отобразить " перед тем, как уйти " диалог. Это совершенно незаметно и позволяет вам взаимодействовать с пользователем до того, как он фактически выполнит действие, чтобы уйти.

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

Недостатком является то, что, конечно, это предположение, что пользователь действительно собирается уйти, но в подавляющем большинстве случаев это правильно.

Для этого я использую:

window.onbeforeunload = function (e) {

}

Он запускается перед тем, как страница выгружается.

В случае, если вам нужно выполнить некоторый асинхронный код (например, отправить сообщение на сервер о том, что пользователь сейчас не сосредоточен на вашей странице), событиеbeforeunloadне даст времени для выполнения асинхронного кода. В случае async я обнаружил, чтоvisibilitychange а также mouseleaveсобытия - лучшие варианты. Эти события запускаются, когда пользователь меняет вкладку, или скрывает браузер, или выводит бегунок из области видимости окна.

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

Я знаю, что на этот вопрос ответили, но в случае, если вы хотите, чтобы что-то срабатывало только при закрытии фактического БРАУЗЕРА, а не только при загрузке страницы, вы можете использовать этот код:

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

В моем примере я очищаю локальное хранилище и предупреждаю пользователя мышами и координатами, только когда браузер закрыт, это будет игнорироваться при всех загрузках страницы из программы.

Благодаря Service Workers можно реализовать решение, аналогичное решению Адама, исключительно на стороне клиента, если браузер поддерживает его. Просто обойдите запросы сердцебиения:

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

API видимости страницы

API видимости страницы предоставляет события, которые можно отслеживать, чтобы узнать, когда документ становится видимым или скрытым.

Когда пользователь сворачивает окно или переключается на другую вкладку, API запускает visibilitychangeсобытие.

Мы можем выполнять действия на основе visibilityState

      function onVisibilityChange() {
  if (document.visibilityState === 'visible') {
     console.log("user is focused on the page")
  } else {
     console.log("user left the page")
  }
}

document.addEventListener('visibilitychange', onVisibilityChange);

Один (немного хакерский) способ сделать это - заменить и связать ссылки с вашего сайта вызовом AJAX на серверную сторону, указывая, что пользователь уходит, а затем использовать тот же блок javascript, чтобы перевести пользователя на внешний сайт, который он покинул. Я просил

Конечно, это не будет работать, если пользователь просто закроет окно браузера или введет новый URL.

Чтобы обойти это, вам, возможно, понадобится использовать setTimeout() Javascript на странице, делая AJAX-вызов каждые несколько секунд (в зависимости от того, как быстро вы захотите узнать, ушел ли пользователь).

Многие люди, задающиеся этим вопросом, возможно, ищут способ определить, когда пользователь покидает страницу, не вызывая всплывающее окно (как в случае сonbeforeunloadсобытие). Если это вы, то ознакомьтесь с Beacon API.

В этом случае не рекомендуется вызывать функцию ajax, поскольку браузеры не гарантируют правильное выполнение запроса... Вот соответствующий отрывок из документации MDN:

Основным вариантом использования Beacon API является отправка аналитики, такой как события на стороне клиента или данные сеанса, на сервер. Исторически веб-сайты использовали для этого XMLHttpRequest, но браузеры не гарантируют отправку этих асинхронных запросов в некоторых обстоятельствах (например, если страница вот-вот будет выгружена). Чтобы бороться с этим, веб-сайты прибегают к различным методам, таким как синхронизация запросов, которые плохо влияют на скорость реагирования. Поскольку запросы маяков являются асинхронными и гарантированно отправляются, они сочетают в себе хорошие характеристики производительности и надежность.

Что вы можете сделать, так это открыть соединение WebSocket при загрузке страницы, при желании отправить данные через WebSocket, идентифицирующий текущего пользователя, и проверить, закрывается ли это соединение на сервере.

Как бы то ни было, это то, что я сделал, и, возможно, это поможет другим, даже если статья устарела.

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-вызов 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);
        }
    }
}

База данных:

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;

Обычно каждые 5 секунд js отправляет сообщение в файл php, который будет отслеживать пользователя и его IP-адрес. Активные пользователи - это просто запись базы данных, отметка времени которой обновляется в течение 5 секунд. Старые пользователи перестают обновлять базу данных. IP-адрес используется только для того, чтобы гарантировать уникальность пользователя, чтобы 2 человека на сайте одновременно не регистрировались как 1 пользователь.

Возможно, не самое эффективное решение, но оно выполняет свою работу.

Другие вопросы по тегам