前端监测用户停留在页面的时长

2,226 阅读3分钟

背景

用户对网页的浏览时长可以判断出当前网页对用户的需求程度,以及当前网页的优先级和重要性。

如果用户在一个网页中停留时长较短的话则可以考虑精简这个网页,如果停留时间较长则可以考虑是否可以对这个网页进一步优化。

应用

  • 多页面应用
  • 单页面应用

如何获取?

多页面应用

在多页面应用中要获取用户的停留时间,需要用到下面几个API

  • onload (页面加载完)
  • onbeforeunload (页面关闭前)
  • onpageshow (页面展示时)
  • onpagehide (页面隐藏时)

Tips:

  1. 无论在页面关闭的时候(点击窗口关闭按钮),还是页面隐藏的时候(点击前进/后端按钮)都会触发 onpagehide
  2. 无论在首次加载还是刷新的时候,都会触发 onpageshow,但是刷新的时候会先触发 onpagehide ,再触发onpageshow,其他两个API也是类似

这里选择使用 onpageshowonpagehide 来实现这个功能,只需要在 onpageshow 设置初始时间值,在 onpagehide 获取最终时间值后求出差值,这个差值就是用户停留在页面中的时长。

let stayTime

window.onpageshow = ()=>{
  stayTime = new Date().getTime()
}

window.onpagehide = ()=>{
  stayTime = new Date().getTime() - stayTime
  let record = localStorage.getItem('data')
  let data = record && JSON.parse(record) || []
  localStorage.setItem('data',JSON.stringify([...data,{user:new Date().getTime(),path:window.location.href,stayTime}]))
}

这里就将这个差值存储到了 localStorage 中,在项目中可以将这个值传给后台,后台再根据这个数据进行一些分析。

单页面应用

单页面应用的路由跳转,但是基于 H5的 History API(browserHistory)Hash(hashHistory) 实现的。

browserHistory

单页面的browserHistory路由是基于H5的History API实现的,我们只要监听popstate就可以知道,点击前进后退按钮后url发生变化,这样就能计算出用户在该页面待了多长时间:

let timeStr

window.addEventListener('onload',(e)=>{
  timeStr = new Date().getTime()
})

window.addEventListener('popstate',()=>{
  let t = new Date().getTime() - timeStr
  timeStr = new Date().getTime()
  console.log('待了时长:'+ t)
})

但是,pushStatereplaceState不会触发popstate,

(也就是点击router-view,$router.push,$router.replace,window.history.pushState,window.history.replaceState不会触发,可以自行试试)

那我们就统计不了用户待在该页面的时长的了;可是解决方法还是有的,只需要重写pushStatereplaceState,然后监听两个自定义事件就行

// 对原函数做一个拓展
let rewriteHis = function(type){
  let origin = window.history[type] // 先将原函数存放起来
  return function(){ // 当window.history[type]函数被执行时,这个函数就会被执行
    let rs = origin.apply(this, arguments) // 执行原函数
    let e = new Event(type.toLocaleLowerCase()) // 定义一个自定义事假
    e.arguments = arguments // 把默认参数,绑定到自定义事件上,new Event返回的结果,自身上市没有arguments的
    window.dispatchEvent(e) // 触发自定义事件,把载荷传给自定义事件
    return rs
  }
}

window.history.pushState = rewriteHis('pushState') // 覆盖原来的pushState方法
window.history.replaceState = rewriteHis('replaceState') // 覆盖原来的replaceState方法

// 监听自定义事件, pushstate事件是在rewriteHis时注册的,不是原生事件
// 当点击router-link 或者 window.history.pushState 或者 this.$router.push 时都会被该事件监听到
window.addEventListener('pushstate',()=>{})

// 监听自定义事件, replacestate事件是在rewriteHis时注册的,不是原生事件
// 当点击window.history.replaceState 或者 this.$router.replace 时都会被该事件监听到
window.addEventListener('replacestate',()=>{})

browserHistory路由变化监听完整代码

let timeStr

let rewriteHis = function(type){
  let origin = window.history[type]
  return function(){
    let rs = origin.apply(this, arguments)
    let e = new Event(type.toLocaleLowerCase())
    e.arguments = arguments
    window.dispatchEvent(e)
    return rs
  }
}

window.history.pushState = rewriteHis('pushState')
window.history.replaceState = rewriteHis('replaceState')

window.addEventListener('onload',(e)=>{
  timeStr = new Date().getTime()
})

window.addEventListener('popstate',()=>{
  let t = new Date().getTime() - timeStr
  timeStr = new Date().getTime()
  console.log('待了时长popstate:'+ t)
})

window.addEventListener('pushstate',()=>{
  let t = new Date().getTime() - timeStr
  timeStr = new Date().getTime()
  console.log('待了时长pushstate:'+ t)
})

window.addEventListener('replacestate',()=>{
  let t = new Date().getTime() - timeStr
  timeStr = new Date().getTime()
  console.log('待了时长replacestate:'+ t)
})

hashHistory

hashHistory 就相对简单,可以直接监听 hashchange 即可

window.addEventListener('hashchange',()=>{
  let t = new Date().getTime() - timeStr
  timeStr = new Date().getTime()
  console.log('待了时长:'+ t)
})

以上

参考文章:juejin.cn/post/690591…