【发布时间】:2010-09-13 22:35:51
【问题描述】:
检测用户是否离开网页的最佳方法是什么?
onunload JavaScript 事件并非每次都起作用(HTTP 请求花费的时间比终止浏览器所需的时间长)。
创建一个可能会被当前浏览器阻止。
【问题讨论】:
标签: javascript
检测用户是否离开网页的最佳方法是什么?
onunload JavaScript 事件并非每次都起作用(HTTP 请求花费的时间比终止浏览器所需的时间长)。
创建一个可能会被当前浏览器阻止。
【问题讨论】:
标签: javascript
尝试onbeforeunload 事件:它在页面卸载之前触发。它还允许您询问用户是否真的想离开。查看演示onbeforeunload Demo。
或者,您可以在他离开时发送Ajax 请求。
【讨论】:
Mozilla 开发者网络对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();
}
});
缺点是用户实际上打算离开当然是猜测,但在绝大多数情况下它是正确的。
【讨论】:
感谢Service Workers,只要浏览器支持,就可以纯粹在客户端实现类似于Adam's 的解决方案。只是绕过心跳请求:
// 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)?
如果你需要做一些异步代码(比如向服务器发送一条消息说用户现在没有关注你的页面),事件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
}
})
【讨论】:
我知道这个问题已经得到解答,但如果您只想在实际浏览器关闭时触发某些东西,而不仅仅是在页面加载发生时,您可以使用以下代码:
window.onbeforeunload = function (e) {
if ((window.event.clientY < 0)) {
//window.localStorage.clear();
//alert("Y coords: " + window.event.clientY)
}
};
在我的示例中,我正在清除本地存储并使用鼠标 y 坐标提醒用户,仅当浏览器关闭时,这将在程序内的所有页面加载中被忽略。
【讨论】:
e 变量)应该被使用:stackoverflow.com/questions/9813445/…
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
一种(有点笨拙)的方法是使用 AJAX 调用到服务器端替换和链接离开您的站点,指示用户正在离开,然后使用相同的 javascript 块将用户带到他们请求的外部网站。
当然,如果用户只是关闭浏览器窗口或输入新的 URL,这将不起作用。
要解决这个问题,您可能需要在页面上使用 Javascript 的 setTimeout(),每隔几秒进行一次 AJAX 调用(取决于您想知道用户是否离开的速度)。
【讨论】:
您可以做的是,在页面加载时打开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);
对 activeUser.php 的 Ajax 调用
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 个用户。
可能不是最有效的解决方案,但确实可以。
【讨论】: