最近公共号内嵌的H5项目上有个需求,要记录个别页面的页面停留时间,后端已经写好接口,只要把页面的停留时间传递给后端就可以了。
一开始我的思路是进入页面的时候记录一个开始时间,离开页面的时候获取一个离开时间,然后相减,把得到的停留时间通过接口传给后端
//计算停留时间
const countStandTime = () => {
const startTime = localStorage.getItem('startTime'); //获取开始时间戳
const lastTime = new Date().valueOf() //获取结束时间戳
const standingTime = Math.floor((lastTime - startTime)/1000) //页面停留时间
...调用接口
};
useEffect(() => {
localStorage.setItem('startTime', new Date().valueOf()); //本地缓存开始时间
return () => {
countStandTime()
localStorage.setItem('startTime', ''); //清空停留时间
};
}, []);
但是这样的话,如果页面刷新了,useEffect返回的函数并不会调用,开始时间会重置为刷新页面的时间,导致缺失一段时间,所以我在最开始判断startTime有没有值,如果有值的话就计算停留时间调用一次接口,相当于刷新之前完成了一次停留的事件,刷新之后再重新计算停留时间
//计算停留时间
const countStandTime = () => {
...
...调用接口
};
useEffect(() => {
const startTime = localStorage.getItem('startTime');
startTime && countStandTime()
localStorage.setItem('startTime', new Date().valueOf()); //本地缓存开始时间
return () => {
countStandTime()
localStorage.setItem('startTime', ''); //清空停留时间
};
}, []);
又有个问题,如果我直接关闭页面的话,这样写是不会触发调用接口的,于是我通过监听window的beforeunload事件,调用接口
//计算停留时间
const countStandTime = () => {
...
...调用接口
};
useEffect(() => {
...
const listener = (ev) => {
countStandTime()
};
window.addEventListener('beforeunload', listener);
return () => {
...
window.removeEventListener('beforeunload', listener);
};
}, []);
这样在页面关闭之前会触发beforeunload事件,调用countStandTime函数计算停留时间并发送给后端
这样写在web端是可以的,但是我在手机上的微信中测试的时候,我发现关闭页面beforeunload函数并没有触发
在网上查了一下,要用监听pagehide事件并且将接口请求改成同步,这个我试了一下,可以触发pagehide事件,但是调用接口仍然失败
而且微信左上角关闭的按钮我也没有找到监听事件
我和老大讨论了几种关于这种情况的解决方案,最后决定将在页面关闭事件中不再请求接口,而是本地缓存开始时间和结束时间,并且在全局的layout中判断有没有开始时间和结束时间,有的话就请求一次接口
//计算停留时间
const countStandTime = (startTime,endTime) => {
const standingTime = Math.floor((endTime - startTime)/1000) //页面停留时间
...调用接口
};
useEffect(() => {
const listener = (ev) => {
localStorage.setItem('endTime', JSON.stringify(referenceDate));
};
window.addEventListener('pagehide', listener);
return () => {
countStandTime()
localStorage.setItem('startTime', ''); //清空停留时间
localStorage.setItem('endTime', ''); //清空停留时间
window.removeEventListener('pagehide', listener);
};
}, []);
//全局layout文件
//计算停留时间
const countStandTime = (startTime,endTime) => {
const standingTime = Math.floor((endTime - startTime)/1000) //页面停留时间
...调用接口
};
useEffect(() => {
const startTime = localStorage.getItem('startTime');
const endTime = localStorage.getItem('endTime');
if (startTime && endTime) {
countStandTime(startTime,endTime)
}
}, []);
这样其实还存在一个问题,如果关闭页面以后,这一次的停留记录并不会马上记录,要等到再次进入这个项目才会调用接口记录上次直接关闭页面的停留时间。
虽然这个并不是最优方案,但是至少能解决问题。如果你有更好的方案,欢迎和我沟通。