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



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Один (немного хакерский) способ сделать это - заменить и ссылки, которые ведут от вашего сайта с вызовом AJAX на стороне сервера, что указывает на то, что пользователь уходит, а затем использовать тот же блок javascript, чтобы перенаправить пользователя на внешний сайт, на котором они просил.
Конечно, это не сработает, если пользователь просто закроет окно браузера или введет новый URL.
Чтобы обойти это, вам, возможно, потребуется использовать на странице Javascript setTimeout (), выполняя вызов AJAX каждые несколько секунд (в зависимости от того, как быстро вы хотите узнать, ушел ли пользователь).
Попробуйте событие onbeforeunload: оно запускается непосредственно перед выгрузкой страницы. Это также позволяет вам спросить, действительно ли пользователь хочет уйти. Смотрите демонстрацию onbeforeunload Demo.
В качестве альтернативы вы можете отправить запрос Аякс, когда он уйдет.
Было бы неплохо для пользователя, если бы вы отслеживали, изменилась ли форма, и запрашивали бы только в том случае, если это произошло - так что это не раздражает.
Также обратите внимание, что различные мобильные браузеры игнорируют результат события (то есть не запрашивают подтверждения у пользователя). Firefox имеет скрытое предпочтение в about: config, чтобы сделать то же самое. По сути, это означает, что пользователь всегда подтверждает, что документ может быть выгружен.
Обратите внимание, что этот метод также активируется, когда пользователь обновляет страницу или отправляет форму.
@Andreas Petersson, у меня та же проблема с целью прервать сеанс пользователя. Как я могу записать набранный URL-адрес, чтобы проверить, принадлежит ли он проекту?
В сети разработчиков 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
});
Я знаю, что на этот вопрос был дан ответ, но в случае, если вы хотите, чтобы что-то запускалось только при закрытии фактического BROWSER, а не только при загрузке страницы, вы можете использовать этот код:
window.onbeforeunload = function (e) {
if ((window.event.clientY < 0)) {
//window.localStorage.clear();
//alert("Y coords: " + window.event.clientY)
}
};
В моем примере я очищаю локальное хранилище и предупреждаю пользователя с помощью координат мыши, только когда браузер закрыт, это будет игнорироваться при загрузке всех страниц из программы.
window.event для меня не определено
Пример Merr Leader неверен, window.event следует использовать только как запасной вариант, например, для более старых версий IE, в других случаях следует использовать параметр события (в данном случае переменная e): stackoverflow.com/questions/9813445/…
Я бы не сказал, что ошибаюсь. Мои примеры отлично работают в IE и Chrome. Мой пример был для сценария, когда пользователь нажимает X (закрыть) в веб-браузере. Может быть, не самый красивый способ, но он работает.
Из 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
Вот альтернативное решение - поскольку в большинстве браузеров элементы управления навигацией (панель навигации, вкладки и т. д.) Расположены над в области содержимого страницы, вы можете обнаружить, что указатель мыши покидает страницу через верхнюю часть, и отобразить диалоговое окно «прежде чем ты уйдешь». Это совершенно ненавязчивый и, он позволяет вам взаимодействовать с пользователем до, который фактически выполняет действие, чтобы покинуть его.
$(document).bind("mouseleave", function(e) {
if (e.pageY - $(window).scrollTop() <= 1) {
$('#BeforeYouLeaveDiv').show();
}
});
Обратной стороной является то, что, конечно, пользователь намеревается покинуть угадать, но в подавляющем большинстве случаев это правильно.
я выгляжу примерно так: я хочу показать что-то ненавязчивое для моего пользователя, прежде чем покинуть свою страницу, я выгляжу что-то вроде события наведения на кнопку возврата, потому что мне нужно запустить событие, прежде чем пользователь нажмет, чтобы вернуться. Я считаю, что лучший способ действительно обнаружить документ тела мыши, и выполнить некоторую логику, чтобы определить, взаимодействовал ли пользователь со страницей.
Как бы то ни было, это то, что я сделал, и, возможно, это может помочь другим, даже если статья устарела.
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 пользователь.
Возможно, не самое эффективное решение, но оно выполняет свою работу.
Благодаря Сервисные работники можно реализовать решение, подобное Адама, исключительно на стороне клиента, если браузер поддерживает его. Просто обходите запросы сердцебиения:
// 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.info('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 отправляет сетевой запрос в / heartbeat, и сервис-воркер его перехватывает.
В случае, если вам нужно сделать асинхронный код (например, отправка сообщения серверу о том, что пользователь сейчас не сфокусирован на вашей странице), событие 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
}
})Что вы можете сделать, так это открыть соединение WebSocket при загрузке страницы, при желании отправить данные через WebSocket, идентифицирующий текущего пользователя, и проверить, закрывается ли это соединение на сервере.
Если вы используете подход «Домой отчета», нет необходимости изменять каждую ссылку на странице.