前端埋点-页面停留时间监控点击事件监控

101次阅读

共计 2925 个字符,预计需要花费 8 分钟才能阅读完成。

要干什么

最近在做前端业务埋点,分享一下怎么写的。
我这边的业务主要有两个地方需要采集:

1、每个页面的访问时间、进入方式、上一页等;2、具体事件的点击
思路:
第一个需求:

监控每个页面的变化,应该在 app.js 里,用 umi.js 提供的 onRouteChange 记录每次路由改变时的数据。
每次路由变化时,发送上一次页面的数据。
发送数据使用 navigator.sendBeacon()
tips:
使用 sendBeacon() 方法会使用户代理在有机会时异步地向服务器发送数据,同时不会延迟页面的卸载或影响下一导航的载入性能。这就解决了提交分析数据时的所有的问题:数据可靠,传输异步并且不会影响下一页面的加载。

那么问题来了?那最后一次页面的数据怎么办呢?

这就需要用到,window.addEventListener('unload', fn),此方法会在 app.js 被卸载的时候调用,在这里我们发送最后一个页面的数据。
还有一些细节的地方,比如收集页面访问时间。
我的方法是:

  1. 在最外层定义一个变量startTime
  2. onRouteChange方法里,用当前时间减去startTime,就得到了页面访问时间。
  3. 然后发送数据
  4. 发送数据后,onRouteChange里再把 startTime 赋值为当前时间。
这里还有一个小问题,就是如果用户没有退出应用,比如他去了其他的应用,那这个时间应该不算做我们页面的访问时间。

所以使用 visibilityChangeEvent 方法,当页面没 hidden 时,计算离开页面的时间。然后在 onRouteChange 里减去这部分时间。

第二个需求:

采集点击事件,我这里用了一个插件,
链接:reportEvent
但是我们把里面的发送事件变成navigator.sendBeacon

var reportEvent = {_ajax: function (obj) {navigator.sendBeacon(obj.url, obj.data);
    },
代码实现:
import moment from 'moment';
import {localget, localset} from 'utils/index';

export const dva = {
  config: {onError(err) {err.preventDefault();
  console.error(err.message);
},
  },
};

// 记录页面数据
let startTime = 0 ;
let historyUrlCode = ['',''];
let historyUrl = ['',''];
let prePageUrl = '';
const FROMAT = 'YYYY-MM-DD HH:mm:ss';
let leaveTime = 0, leaveTimeStart = 0, preAction ='';

let hiddenProperty = 'hidden' in document ? 'hidden' :  'webkitHidden' in document ? 'webkitHidden' :  'mozHidden' in document ? 'mozHidden' :  null;
let visibilityChangeEvent = hiddenProperty.replace(/hidden/i, 'visibilitychange');
let onVisibilityChange = function(){
// 应用是否在前台监听
console.log(document[hiddenProperty], new Date());
if(document.hidden){
  // 不在当前页面
  leaveTimeStart = new Date();} else {if(leaveTimeStart !== 0){leaveTime = new Date() - leaveTimeStart;
    leaveTimeStart = 0
  }
}
}
document.addEventListener(visibilityChangeEvent, onVisibilityChange);

window.addEventListener('unload', function(event) {const { currentPlatform={}, pageEventList=[]} = window.g_app._store.getState().user;
  let endTime = new Date();
  let showTime = Math.ceil((endTime - startTime - leaveTime)/1000);
  historyUrlCode = [UrlToCode(historyUrl[0], pageEventList), UrlToCode(historyUrl[1], pageEventList)];
  // 发送的数据
  let data ={...}
  navigator.sendBeacon('url', JSON.stringify(data));
});

export function onRouteChange({location, routes, action}) {
  let showTime,endTime;
  // 页面访问埋点
  if(startTime !== 0){endTime = new Date();
showTime = Math.ceil((endTime - startTime - leaveTime)/1000);
  }
  // 获取 model 里的 state
  const {currentPlatform={}, pageEventList=[]} = window.g_app._store.getState().user;
  historyUrlCode = [UrlToCode(historyUrl[0], pageEventList), UrlToCode(historyUrl[1], pageEventList)];
  localset("historyUrlCode", historyUrlCode);
  // 发送的数据
  
  let data = {...};

  // 发送
  if(startTime !== 0) navigator.sendBeacon('url', JSON.stringify(data));
  // 进入一个新页面,重置
  startTime = new Date();
  historyUrl = [historyUrl[1], location.pathname]
  prePageUrl = location.pathname;
  leaveTime = 0;
  preAction = action;
}

// url 转成对应页面编码
function UrlToCode (url , codeList) {
  let res;
  if(url.includes('/content/')){
// 案例, 特殊处理
res = codeList.filter(item => item.pageUrl === '/content')[0].pageEventCode;
console.log(res)
  } else {res = codeList.filter(item => item.pageUrl === url)
res = (res[0] && res[0].pageEventCode) || ''
  }
  return res
}

正文完
 0