vue项⽬前端埋点
埋点⽅案的确定
业界的埋点⽅案主要分为以下三类:
代码埋点:在需要埋点的节点调⽤接⼝,携带数据上传。如百度统计等;
可视化埋点:使⽤可视化⼯具进⾏配置化的埋点,即所谓的「⽆痕埋点」,前端在页⾯加载时,可以读取配置数据,⾃动调⽤接⼝进⾏埋点。如开源的Mixpanel;
⽆埋点:前端⾃动采集全部事件并上报埋点数据。如国内的神策数据等;
在当时排期紧凑,⼈⼒紧缺的情况下,显然不允许我们去开发可视化埋点⽅案和⽆埋点⽅案,所以只能采取代码埋点⽅案。
命令式埋点
命令式埋点,顾名思义,开发者需要⼿动在需要埋点的节点处进⾏埋点。如点击按钮或链接后的回调函数、页⾯ready时进⾏请求的发送。⼤家肯定都很熟悉这样的代码:
/
/ 页⾯加载时发送埋点请求
$(document).ready(function(){
// ... 这⾥存在⼀些业务逻辑
sendRequest(params);
});
// 按钮点击时发送埋点请求
$('button').click(function(){
// ... 这⾥存在⼀些业务逻辑
sendRequest(params);
});
可以很容易发现,这样的做法很有可能会将埋点代码侵⼊业务代码,这使整体业务代码变得繁琐,容
易出错,且后续代码会愈加膨胀,难以维护。所以,我们需要让埋点的代码与具体的业务逻辑解耦,即 声明式埋点 ,从⽽提⾼埋点的效率和代码的可维护性。
声明式埋点
理论上,声明式埋点只需要关注两个问题:
需要埋点的DOM节点;
所需携带的数据
因此,可以很快想出⼀个声明式埋点的⽅法:
// key表⽰埋点的唯⼀标识;act表⽰埋点⽅式
<button data-stat="{key:'111', act: 'click'}">埋点</button>
那么可以去遍历DOM树,到 [data-stat] 的节点,给这个button绑上click事件,把这些参数在回调函数中通过请求发出去。
在DOM节点(html)上声明埋点,与业务逻辑(通常在Javascript⽂件中)就解耦了。调⽤也很⽅便。
看起来很美,但这样就能解决问题了吗?显然是不够的。还需要解决以下问题:
遍历DOM树的时机问题,⼀个简单的例⼦,⼀个表格的⾏数据是通过异步加载,⽽表格⾏中的操作按钮需要埋点,那么在DOM ready的时候去遍历,显然是⽆法到的
绑定埋点事件次数的问题,怎样保证埋点事件不会被重复绑定到元素上,⼀次操作发了N个埋点请求?
如何处理特有的埋点⾏为,如页⾯展现埋点,区域展现埋点?
如何在解绑时,销毁已绑定的事件?
jquery在项目里是干啥的
1.⾃定义指令实现埋点数据统计
在项⽬中通常需要做数据埋点,这个时候,使⽤⾃定义指令将会变⾮常简单
在项⽬⼊⼝⽂件 main.js 中配置我们的⾃定义指令
// 坑位埋点指令
Vue.directive('stat', {
bind(el, binding) {
el.addEventListener('click', () => {
const data = binding.value;
let prefix = 'store';
if (OS.isAndroid || OS.isPhone) {
prefix = 'mall';
}
ty: `${prefix}_${pe}`,
dc: data.desc || ''
}, 'n');
}, false);
}
});
2.使⽤路由拦截统计页⾯级别的 PV
由于第⼀次在单页应⽤中尝试数据埋点,在项⽬上线⼀个星期之后,数据统计后台发现,⾸页的 PV 远远⾼于其它页⾯,数据很不正常。后来跟数据后台的⼈沟通询问他们的埋点统计原理之后,才发现其中的问题所在。
传统应⽤,⼀般都在页⾯加载的时候,会有⼀个异步的 js 加载,就像百度的统计代码类似,所以我们每个页⾯的加载的时候,都会统计到数据;然⽽在单页应⽤,页⾯加载初始化只有⼀次,所以其它页⾯的统计数据需要我们⾃⼰⼿动上报
解决⽅案
使⽤ vue-router 的 beforeEach 或者 afterEach 钩⼦上报数据,具体使⽤哪个最好是根据业务逻辑来选择。
const analyticsRequest = (to, from) => {
// 只统计页⾯跳转数据,不统计当前页 query 不同的数据
// 所以这⾥只使⽤了 path, 如果需要统计 query 的,可以使⽤ to.fullPath
if (to.path !== from.path) {
url: `${location.protocol}//${location.host}${to.path}`
});
}
};
router.beforeEach((to, from, next) => {
if (to.matched.some(record => quiresAuth)) {
// 这⾥做登录等前置逻辑判断
/
/ 判断通过之后,再上报数据
...
analyticsRequest(to, from);
} else {
// 不需要判断的,直接上报数据
analyticsRequest(to, from);
next();
}
});
在组件中使⽤我们的⾃定义指令
image.png
基于 jquery + widget 的⽼项⽬,
那么在这些项⽬中的DOM操作是jquery甚⾄原⽣DOM API来实现,Vue的⾃定义指令就⽆法⼯作
基于MutationObserver API的Mixin
MutationObserver是在DOM3标准中提出的标准API,提供让开发者感知到在某⼀个DOM节点变更的能⼒。可以监听以下场景:childList: ⽬标节点的⼦节点插⼊删除引起的变更
attributes: ⽬标节点属性改变引起的变更
characterData: ⽬标节点的⽂本节点改变引起的变更,如通过appendData()等
subtree: ⽬标节点的⼦孙节点改变引起的变更
attributeOldValue:当attribute监听被设定为true时,可以记录改变前的属性值
characterDataOldValue:当characterData监听被设定为true时,可以记录改变前的属性值
attributeFilter:可以设定需要监听的属性列表
但为了保证MutationObserver可以在所有浏览器上正常⼯作,我们仍然引⼊了这个API的polyfill,详情可见。
在此能⼒的前提下,我们就可以在任意的DOM操作下触发Vue进⾏重新解析指令。
我们将 MutationObserver 封装进⼀个 Vue mixin , ⾮Vue应⽤的业务代码只需要引⼊这个mixin,这样也可以很好地解耦。
详细的实现原理可以见以下伪代码:
let observer;
export default {
ready() {
// 开启监听
observer = new MutationObserver(mutations => {
this.$compile(this.$el);
});
observer.observe(this.$el, config);
},
destroyed() {
// 清理⼯作
observer.disconnect();
observer.takeRecords();
}
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。