埋点(vue
)
主要分为4个函数,pageInteval
、pageTimelyRecord
、setUrlModelFn
、recordTrackId
。主要依托于路由守卫。主要记录页面时长、最后一个页面的时候、页面的映射路径
pageInteval
:主要是用于记录定时任务。说明,因为我们无法记录最后一个页面的时长,故采用将数据记录在localStorage
里面,然后通过下一次进入页面的时候发起请求!具体代码如下:
let startTime = Date.now(); // 页面进入的开始时间
let currentTime = null; // 当前时间
let timer = null;
/*页面定时存储,主要记录最后一个页面*/
export const pageInteval = (to, from) => {
// 当在登入页面
if(from.path === '/login') {
const firstAllInfo = JSON.parse(localStorage.getItem('XXX'));
if(firstAllInfo) {
axios....// 向后端发起请求
localStorage.setItem('xxx', null);
request.setTrackId('-1'); // 页面来源id重新从-1开始
}
}
if(timer) {
clearInterval(timer);
}
const recordStaticInfo = {
pointUrl: to.path,// 因为是记录最后一个页面所以是to的路径
pointType: 'page', // 为页面类型
pointCustomization: JOSN.stringify(to.query) === '{}' : JSON.stringify(to.query)// 页面的附属参数
}
// 存储任务
timer = setInterval(async () => {
// 页面跳转后记录一下当前时间
currentTime = currentTime - startTime;
const allInfo = {
...recordInfo,
pointSource: await request.getTrackId(),
pageStayTime: Math.ceil(diff/1000);
}
localStorage.setItem('xxx', JSON.stringify(allInfo));
}, 5000);
// 初始化开始日期
startTime = Date.now();
}
pageTimelyRecord
与 pageInteval
函数类似,pageTimelyRecord
主要是路由路由跳转的时候获取from.path
的情况信息,这边就不再展开去讲了。
setUrlModelFn
主要是记录页面的映射路径,有朋友就要讲了,何为映射路径。那我就要说道说道了。其实也很简单,就是说,你当前页面在第四层级,那么我就要将前面三层的路径也要传给后端,就是 first->second->third->fouth
具体代码实现如下。
function setUrlModelFn(direction) {
// 补齐数组项,如果这边不补齐的化,后面对象查找就会报错, 因为我放的数据是存在路由meta的
direction.meta.mapPaths = direction.meta.mapPaths || [];
if(direction.meta.mapPaths.length < 4) {
// 这里明确确定 这里只有4级菜单
const sur = 4 - direction.meta.mapPaths.length;
for(let i = 0; i < sur; i++) {
// 用于补齐尾项
direction.meta.mapPaths.push({id:'',name:'',pId: ''});
}
}
const [
{id: firstMenuId, pId: firstMenuPid},
{id: secondMenuId, pId: secondMenuPid},
{id: thirdMenuId, pId: thirdMenuPid},
{id: fourMenuId, pId: fourMenuPid}
] = direction.meta.mapPaths
// 这一步设置叶子节点菜单和当前叶子菜单的父级
request.setUrlModel({
urlLeafId: fourMenuId || thirdMenuId || secondMenuId || firstMenuId,
urlParentId: fourMenuPid || thirdMenuPid || secondMenuPid || firstMenuPid
})
}
// 传入to(下一个页面的相关信息,需要配合路由守卫去做)
setUrlModelFn(to);
在这里有一段关键的代码,就是寻找对应的映射路径,这里我单独拿出来,未来也许有需要。看如下代码。
// 获取映射路径
function recordMapPath(array, targetId) {
const parentSubjectStock = [];// 存储父节点
let going = true;// 是否已经找到要查找到的节点(false表示已找到不再继续)
let findParentNode = function(array, id) {
array.forEach((item) => {
if(!going) {// 没有找到直接退出
return
}
parentSubjectStock.push(item);
if(item.id === id) {
going = false
} else if(item.children && item.children.length > 0) {
findParentNode(item.children, id);
} else {
// 如果都没找到则剔除当前这一项,以免污染数据
parentSubjectStock.pop();
}
})
// 剔除一开始就找不到目标id的情况
if(going) {
parentSubjectStock.pop();
}
}
findParentNode(array, targetId);
// 返回自己想要的映射路径
return parentSubjectStock.map((item) => ({
id: item.id,
name: item.name,
pId: item.pId
}))
}
/**
@array 是有层级结构的菜单路径
@id 对应的菜单叶子节点id
*/
recordMapPath(array, id)
上面这段代码就是说要找到此菜单所对应的菜单路径。
最后说下在路由守卫里面的情况吧,看如下代码和注释。
/*
在路由前置守卫 beforeEach上面,配合页面跳转权限进行的判断
*/
// 如果当前角色在下一个页面有权限
const hasPermision = (role, route) => {
let meta = route.meta;
if(meta && meta.roles) return meta.roles.includes(role)
return true
}
if(hasPermision(role, to)) {
// 这里避免了在根路径和/login页面的时候发送接口请求
if(from.path !== '/' && to.path !== '/login') {
pageInteval(to, from);
}
// 这里避免在根路径和在重定向页面去发送接口请求
if(from.path !== '/' && from.path !== 'redirect/index') {
pageTimelyRecord(to, from);
} else {
next();
}
}
最后,这边页面时长的埋点算是结束了!其实埋点这个部分非常的有广度,涉及的方方面面,包括页面错误埋点,按钮点击统计,页面跳转路径等等等多方面,未来有机会将会不断的补充和完善此部分的代码。