提问人:Richard Knop 提问时间:1/12/2011 更新时间:9/21/2023 访问量:110710
如何衡量在页面上花费的时间?
How to measure a time spent on a page?
答:
我认为最好的方法是将时间存储在 onload 中,并在 cookie 中卸载事件处理程序,然后在服务器端脚本中分析它们
评论
我想说的是,最好的办法是跟踪服务器上每个会话 ID 的请求时间。用户在最后一页花费的时间是当前请求的时间与前一个请求的时间之间的差值。
这不会捕获用户访问的最后一个页面(即当没有其他请求时),但我仍然会采用这种方法,否则您必须在 提交请求,这将非常容易出错。onunload
评论
如果您使用 Google Analytics,他们会提供此统计数据,尽管我不确定他们是如何获得的。
如果你想滚动自己的,你需要有一些AJAX请求被发送到你的服务器进行日志记录。
jQuery有一个.unload(...)方法,你可以这样使用:
$(document).ready(function() {
var start = new Date();
$(window).unload(function() {
var end = new Date();
$.ajax({
url: "log.php",
data: {'timeSpent': end - start},
async: false
})
});
});
在此处查看更多信息:http://api.jquery.com/unload/
这里唯一需要注意的是,它使用了 javascript 的 beforeunload 事件,它并不总是有足够的时间发出这样的 AJAX 请求,因此合理地你会丢失大量数据。
另一种方法是定期轮询服务器,发送某种类型的“STILL HERE”消息,这些消息可以更一致地处理,但显然成本更高。
评论
$_SESSION
$_SESSION
async : false
end
公认的答案是好的,但是(作为替代方案)我已经在一个小的JavaScript库中做了一些工作,该库可以计算用户在网页上的时间。它还有一个额外的好处,即更准确地(尽管并不完美)跟踪用户实际与页面交互的时间。它忽略了用户切换到不同选项卡、空闲、最小化浏览器等时间。接受的答案中建议的 Google Analytics 方法有一个缺点(据我所知),它只检查您的域何时处理新请求。它将以前的请求时间与新的请求时间进行比较,并将其称为“在网页上花费的时间”。它实际上不知道是否有人正在查看您的页面,是否最小化了浏览器,自上次加载您的页面以来已将选项卡切换到 3 个不同的网页等。
编辑:我更新了示例以包含当前的 API 用法。
编辑 2:更新托管项目的域
https://github.com/jasonzissman/TimeMe.js/
其用法示例:
在您的页面中包括:
<!-- Download library from https://github.com/jasonzissman/TimeMe.js/ -->
<script src="timeme.js"></script>
<script type="text/javascript">
TimeMe.initialize({
currentPageName: "home-page", // page name
idleTimeoutInSeconds: 15 // time before user considered idle
});
</script>
如果您想自己向后端报告时间:
xmlhttp=new XMLHttpRequest();
xmlhttp.open("POST","ENTER_URL_HERE",true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
var timeSpentOnPage = TimeMe.getTimeOnCurrentPageInSeconds();
xmlhttp.send(timeSpentOnPage);
TimeMe.js还支持通过 websocket 发送计时数据,因此您不必尝试将完整的 HTTP 请求强制发送到事件中。document.onbeforeunload
评论
根据正确的答案,我认为这不是最好的解决方案。因为根据 jQuery 文档:
卸载事件的确切处理方式因版本而异 浏览器的版本。例如,某些版本的 Firefox 会触发 事件,但当链接被关注时,而不是在窗口关闭时。在 实际使用,行为应在所有支持的浏览器上进行测试 并与类似的 beforeunload 事件形成对比。
另一件事是,您不应该在文档加载后使用它,因为时间减去的结果可能是假的。
因此,更好的解决方案是将其添加到本节末尾的事件中,如下所示:onbeforeunload
<head>
<script>
var startTime = (new Date()).getTime();
window.onbeforeunload = function (event) {
var timeSpent = (new Date()).getTime() - startTime,
xmlhttp= new XMLHttpRequest();
xmlhttp.open("POST", "your_url");
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
var timeSpentOnPage = TimeMe.getTimeOnCurrentPageInSeconds();
xmlhttp.send(timeSpent);
};
</script>
当然,如果您想使用空闲检测器计算时间,您可以使用:
https://github.com/serkanyersen/ifvisible.js/
TimeMe 是我粘贴在上面的包的包装器。
除了 Jason 的回答之外,这里有一小段代码,如果您不想使用库,它应该可以解决问题,它会考虑用户何时切换选项卡或聚焦另一个窗口。
let startDate = new Date();
let elapsedTime = 0;
const focus = function() {
startDate = new Date();
};
const blur = function() {
const endDate = new Date();
const spentTime = endDate.getTime() - startDate.getTime();
elapsedTime += spentTime;
};
const beforeunload = function() {
const endDate = new Date();
const spentTime = endDate.getTime() - startDate.getTime();
elapsedTime += spentTime;
// elapsedTime contains the time spent on page in milliseconds
};
window.addEventListener('focus', focus);
window.addEventListener('blur', blur);
window.addEventListener('beforeunload', beforeunload);
评论
<body onLoad="myFunction()">
<script src="jquery.min.js"></script>
<script>
var arr = [];
window.onbeforeunload = function(){
var d = new Date();
var n = d.getTime();
arr.push(n);
var diff= n-arr[0];
var sec = diff/1000;
var r = Math.round(sec);
return "Time spent on page: "+r+" seconds";
};
function myFunction() {
var d = new Date();
var n = d.getTime();
arr.push(n);
}
</script>
用𝗽𝗲𝗿𝗳𝗼𝗿𝗺𝗮𝗻𝗰𝗲.𝗻𝗼𝘄()
运行内联代码以获取用户到达页面的时间会阻止页面的加载。相反,请使用 which 显示自用户首次导航到页面以来经过了多少毫秒。但是,由于时间重新同步和闰秒等因素,时钟时间可能与导航时间相差一秒或更多。 在 IE10+ 和所有常青浏览器中受支持(evergreen=为娱乐而生,不以营利为目的)。今天仍然存在的最早的Internet Explorer版本是Internet Explorer 11(最后一个版本),因为Microsoft在2014年停止了Windows XP。performance.now()
Date.now
performance.now()
(function(){"use strict";
var secondsSpentElement = document.getElementById("seconds-spent");
var millisecondsSpentElement = document.getElementById("milliseconds-spent");
requestAnimationFrame(function updateTimeSpent(){
var timeNow = performance.now();
secondsSpentElement.value = round(timeNow/1000);
millisecondsSpentElement.value = round(timeNow);
requestAnimationFrame(updateTimeSpent);
});
var performance = window.performance, round = Math.round;
})();
Seconds spent on page: <input id="seconds-spent" size="6" readonly="" /><br />
Milliseconds spent here: <input id="milliseconds-spent" size="6" readonly="" />
我发现使用 beforeunload 事件是不可靠的,实际上经常失败。通常,在发送请求之前,页面已被销毁,并且您会收到“网络故障”错误。
正如其他人所说,没有万无一失的方法可以判断用户在页面上停留了多长时间。但是,您可以发送一些线索。
点击和滚动是相当公平的指标,表明有人正在积极查看该页面。我建议侦听点击和滚动事件,并在触发请求时发送请求,尽管频率不超过每 30 或 60 秒一次。
人们可以在计算中使用一些智能,例如,如果每 30 秒左右触发一个事件,持续 5 分钟,那么 30 分钟内没有事件,然后再触发几个事件,很有可能,用户在 30 分钟内喝咖啡。
let sessionid;
function utilize(action) {
// This just gets the data on the server, all the calculation is done server-side.
let href = window.location.href;
let timestamp = Date.now();
sessionid = sessionid || timestamp;
let formData = new FormData();
formData.append('sessionid', sessionid);
formData.append('timestamp', timestamp);
formData.append('href', href);
formData.append('action', action || "");
let url = "/php/track.php";
let response = fetch(url, {
method: "POST",
body: formData
});
}
let inhibitCall = false;
function onEvent() {
// Don't allow an update any more often than every 30 seconds.
if (!inhibitCall) {
inhibitCall = true;
utilize('update');
setTimeout(() => {
inhibitCall = false;
}, 30000);
}
}
window.addEventListener("scroll", onEvent);
window.addEventListener("click", onEvent);
utilize("open");
我想我已经找到了一个简单的解决方案。
只需使用重复间隔和 LocalStorage 以及一些 PHP(或任何服务器端语言)
设置 LocalStorage
if (typeof localStorage.getItem("time_spent_current") === "undefined" || localStorage.getItem("time_spent_current") == null) {
localStorage.setItem("time_spent_current", -5);
}
每 5 秒向本地存储添加一次时间
var intervalId = window.setInterval(function(){
// call your function here
var val = localStorage.getItem("time_spent_current");
var time_spent_current = parseInt(val) + 5;
localStorage.setItem("time_spent_current", time_spent_current);
console.log(time_spent_current);
}, 5000);
如果要将数据更新到服务器,请上传数据 每个新会话。
<?php if(!isset($_SESSION["time_spent_current"])){ ?>
$(document).ready(function() {
var start = new Date();
$(window).unload(function() {
var end = new Date();
$.ajax({
url: "log.php",
data: {'timeSpent': time_spent_current},
async: false
})
});
});
<?php
$_SESSION["time_spent_current"] = 1;
}
?>
P.s.:使用Kevin Dolan的脚本(最初接受的答案)将数据上传到服务器
得票最多的答案都不适合我。因为有可能在不转移焦点的情况下打开页面(例如,使用鼠标中键或“Ctrl”+左键组合时)。
TimeMe.js有一个可怕的缺点。当您在新选项卡中打开链接时,它不会获得焦点(“Ctrl”+ 左键单击链接),库会启动该选项卡的活动计数器,就好像该选项卡处于焦点中一样。TimeMe.js仅在用户激活然后离开选项卡时停止计数器(该操作会触发窗口的模糊事件)。
我建议大家看看页面可见性API
在我看来,它提供了一个简单可靠的解决方案来检查选项卡是否实际处于活动状态(或在屏幕上可见)。
document.addEventListener("visibilitychange", () => {
if (document.hidden) {
// The tab is in the focus.
// Let's measure a user time on the page
} else {
// Tab is not in the focus
// Stop the counter
}
});
否则,您可以将条件放在时间间隔循环中:document.hidden
let elapsedTime = 0;
setInterval(function() {
if (!document.hidden) {
elapsedTime += 1;
// Send to server or do other stuff
console.log(elapsedTime);
}
}, 1000);
评论