Vue单页面应用中业务数据的埋点和上报
由于数据维度非常多,这里仅说业务数据的埋点及其上报。之前有一篇文章介绍了 Vue 中使用 自定义组件 和 全局混入 做 PV 数据的上报,经过这几个月的开发我对此也有了更深的了解。
业务数据处理 PV 以外,还有很多,这篇文章将围绕业务数据来一一解答。
简述
由于前端涉及到用户数据的维度较多,这里依然是探讨业务数据的上报。实现需求的前提是尽可能不去改动现有的组件,所以实现这套组件之前,可以先明确下几个问题:
- 哪些数据可以自动收集,哪些数据需要埋点;
- 数据埋点的方式有哪些;
- 如何确保上报一段时间内的唯一性;
- 如何处理页面的切换、路由和跳转数据;
下面我们将对上面的过程逐一解决。
自动收集
其实页面中有很多数据是可以自动收集的,自动收集的意思不是说万千不用开发者参与,而是表示不用按照特定的规则来处理。
例如之前有一篇文章介绍的点击数据的上报,就是可以自动收集的,所有需要进行统计点击的组件的都可以通过自定义指令或者全局混入的方式来实现,这种不需要对组件做特殊处理,一劳永逸。
同理的,除了上面的点击数据以外,组件的展示数据也是可以自动收集的,例如一些异步组件在用户没有触发到功能或者路由的时候是不会渲染的,只有用户明确触发了才会异步加载,那么这样的组件如果需要进行显示统计,也是可以自动收集的。
关于这些自动收集的数据,之前的博文有介绍基于 Vue 的 自定义指令
或者 全局混入
就可以实现。
数据埋点
埋点也是为了能自动收集,但是需要定制化。埋点的意思,就是在需要上报的组件上增加一个自定义指令,或者 data
属性。
在之前的例子中,自定义指令和全局混入的时候我们都阻止了冒泡,这次则不再阻止,相反的,我们还将利用事件冒泡。当任一个受监听的组件触发了事件,这个事件将向上冒泡,遇到绑定了自定义指令的组件,则上报数据,如果冒泡一直没有被监听拦截,则不上报。
以自定义指令为例:
Vue.directive("databoss", {
bind: function (el, binding) {
el.databossListerner = () => {
// 如果 v-databoss 被绑定为函数,则上报函数的返回值
if (typeof binding.value === 'function') {
databoss.postData(binding.value());
}
// 如果绑定的不是函数,则上报绑定的值
else {
databoss.postData(this.binding.value)
}
}
// 添加事件监听
el.addEventListener("click", el.databossListerner);
},
unbind: function (el) {
if (!el.databossListerner) return;
el.removeEventListener("click", el.databossListerner);
}
})
然后假设有一个组件需要埋点:
<template>
<div class="home">
<meter-table v-databoss="postData"/>
</div>
</template>
可以看到我们给 meter-table
组件使用 databoss
指令进行了埋点,并且给埋点赋值为 postData
。此时,我们可以在 .Vue 文件中来定义这个 postData ,可以定义在 data 数据对象中,也可以定义在 methods 属性中。
加入定义在 data 属性中,那么 postData 将是一个数据,上报时只需要看普通数据上报即可。
export default {
data: () => {
return {
// 上报数据为一个 JSON 对象
postData: {
pagename: 'mainpage',
event: 'meter_table_click',
}
}
},
methods: {
...
}
}
postData 也可以是一个函数,如果是一个函数,那么函数的返回值将作为上报的数据,此时要求函数必须是同步的,不能异步。
export default {
data: () => {
return {
...
}
},
methods: {
postData() {
return {
pagename: 'mainpage',
event: 'meter_table_click',
}
},
...
}
}
设备唯一性
这里的唯一性并不是真正意义的设备唯一性,而是在一定时间内,一定情况下的唯一性。
我们知道,Web页面是一个沙盒,我们不能直接去获取设备的标识码,所以我需要在初次载入页面的时候为 Web APP 生成一个唯一的标识,这个标识将伴随着整个应用的生命周期。
设备属性的确认主要有两个目的:
- 统计设备属性,例如设备的类型、平台等信息;
- 对于登录用户,确定登录用户的设备平台;
生成唯一标识后,可以将标识保存在 cookie 或者 localStorage 中,这里我们首选 localStorage,避免对 cookie 的污染,另一方面 localStorage 也可以保存更多的数据。
let did = localStorage.getItem('iotclient');
if (!did) {
did = {
key: Date.now() + (Math.random() + '').substr(-6),
createAt: parseInt(Date.now() / 1000)
}
localStorage.setItem('iotclient', did);
}
路由数据
路由数据可以通过 Vue router 的 afterEach
方法来实现,在一个页面完成路由后进行上报。
router.afterEach((to, from) => {
databoss.postData({
type: "page_router",
to,
from
})
})
不采用 beforeEach
是因为我们必须确定页面已经成功跳转,所以不应该在 beforeEach 中劫持。
页面跳转数据
不同于页面路由,页面跳转表示从一个页面跳转到另一个页面,例如从一个单页面应用跳转到另一个单页面应用,如果是这种情况,那么上面的几种方法就不太适用了。主要原因在于数据可能还没有上报完,页面就已经完成卸载。
针对这种情况,我的方案是在页面跳转前先在 localStorage 中写一个待上报的数据,然后在页面重新跳转回来的时候将 localStorage 中待上报的数据进行上报清空。
postData.push({
pagename: 'mainpage',
event: 'meter_table_click',
createAt: parseInt(Date.now() / 1000)
})
localStorage.setItem("postData", JSON.stringify(postData))
location.href = new_page_url;