Найкращий спосіб виявити, коли користувач залишає веб-сторінку?


195

Який найкращий спосіб виявити, якщо користувач залишає веб-сторінку?

onunloadПодія JavaScript не працює кожен раз , коли (запит HTTP займає більше часу , ніж час , необхідний для завершення браузер).

Створення його, ймовірно, буде заблоковано поточними браузерами.

Відповіді:


219

Спробуйте onbeforeunloadподію: вона запускається безпосередньо перед завантаженням сторінки. Це також дозволяє запитати, чи дійсно користувач хоче піти. Дивіться демонстраційну програму onbeforeunload Demo .

Крім того, ви можете відправити запит Ajax, коли він виїжджає.


3
Користувачеві було б добре, якби ви відстежували, чи змінилась форма, і лише підказували, якщо це було - так це не дратує.
adam0101

3
Зауважте також, що різні мобільні браузери ігнорують результат події (тобто вони не просять у користувача підтвердження). Firefox має приховані переваги в about: config робити те саме. По суті це означає, що користувач завжди підтверджує, що документ може бути завантажений.
MJB

2
Зауважте, що цей метод також викликає, коли користувач оновлює сторінку або подає форму.
Зайцев Дмитро

@Andreas Petersson, я маю те саме завдання з метою припинити користувальницьку сесію. Як я можу захопити URL, набраний, щоб перевірити, чи належить він проекту?
Jcc.Sanabria

21

Мережа розробників Mozilla має хороший опис та приклад завантаження .

Якщо ви хочете попередити користувача перед виходом із сторінки, якщо ваша сторінка забруднена (тобто якщо користувач ввів якісь дані):

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

Ось альтернативне рішення - оскільки в більшості браузерів елементи управління навігацією (панель навігації, вкладки тощо) розташовані над областю вмісту сторінки, ви можете виявити вказівник миші, що залишає сторінку вгорі, і відобразити " перед відходом " діалог. Це абсолютно ненав'язливо, і дозволяє вам взаємодіяти з користувачем, перш ніж вони дійсно виконають дію, щоб вийти.

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

Мінусом є те, що, звичайно, це здогад, що користувач насправді має намір піти, але в переважній більшості випадків це правильно.


я шукаю щось на кшталт, я хочу показати щось ненав'язливе для свого користувача, перш ніж залишати свою сторінку, я шукаю щось на зразок події наведення на кнопку назад, тому що мені потрібно запустити подію, перш ніж користувач натисне, щоб повернутися назад. Я вважаю, що найкращий спосіб - це дійсно виявити документ тіла про залишення миші та виконувати певну логіку, щоб визначити, чи користувач взаємодіяв зі сторінкою.
Леонардо Суза Пайва

8

Для цього я використовую:

window.onbeforeunload = function (e) {

}

Він запускається безпосередньо перед завантаженням сторінки.


1
Версії Opera 12 та старіших версій не підтримують це ... zachleat.com/web/…
Сайрус

Чим це краще, ніж попередні два відповіді, які дають те саме рішення onbeforeunload,?
Дан Даскалеску

5

Я знаю, що на це питання відповіли, але якщо ви хочете, щоб щось спрацьовувало, коли фактичний BROWSER закритий, а не лише тоді, коли відбувається завантаження сторінки, ви можете використовувати цей код:

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

У своєму прикладі я очищаю локальне сховище та попереджую користувача за допомогою команд мишей y, лише коли браузер закритий, це буде ігноровано при всіх завантаженнях сторінки з програми.


window.event для мене не визначений
Карл Глазер

Приклад Merr Leader невірний, window.event слід використовувати лише як резервний приклад, наприклад, для старих версій IE, в інших випадках eслід застосовувати параметр події ( змінна в цьому випадку: stackoverflow.com/questions/9813445/ …
Sk8erPeter

Не вдалося б сказати, що я помиляюся. Мої приклади добре працюють для мене в IE та Chrome. Моїм прикладом був сценарій, коли користувач натискає X (закрити) у веб-браузері. Можливо, не найкрасивіший спосіб, але це працює.
Ведучий Merr

З 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
Робін Ніл

3

Один (злегка хакітний) спосіб зробити це заміна та посилання, які ведуть далеко від вашого веб-сайту за допомогою AJAX-дзвінка на сторону сервера, що вказує, що користувач покидає, а потім використовуйте той самий блок javascript, щоб перевезти користувача на зовнішній сайт, який вони Ви просили.

Звичайно, це не спрацює, якщо користувач просто закриє вікно браузера або введе нову URL-адресу.

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


4
Якщо ви використовуєте домашній підхід до звіту, не потрібно змінювати кожне посилання на сторінці.
Вінко Врсалович

3

Завдяки сервісним працівникам , можна реалізувати рішення, подібне до Адамового, виключно на стороні клієнта, за умови, що браузер його підтримує. Просто обходьте запити серцебиття:

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

Ви мали на увазі, що десь у клієнтському коді потрібно бути setInterval(() => fetch('/heartbeat'), 5000)?
Дан Даскалеску

@DanDascalescu Правильно. Код JS робить мережевий запит на / серцебиття, і сервісний працівник перехоплює його.
Джефрі Свіні

2

У випадку, якщо вам потрібно зробити якийсь асинхронний код (наприклад, надіслати повідомлення серверу, що користувач зараз не зосереджений на вашій сторінці), подія beforeunloadне дасть часу асинхронному коду для запуску. У випадку асинхронності я виявив, що 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
    }  
})


0

Для чого це варте, це те, що я зробив, і, можливо, він може допомогти іншим, навіть якщо стаття стара.

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 користувач.

Можливо, це не найефективніше рішення, але воно справляється з цим.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.