要干什么

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

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}