目标
- 使用简单;
- 减少代码侵入性,不影响业务代码阅读
简述
- 埋点一般是按页面来管理的;
- 埋点的事件类型一般分为:点击、曝光和页面的进入和离开;
- 埋点的实质就是在恰当的时机去发送请求,上送业务需要的参数
按页面管理埋点
在每个页面目录下创建events.js
,管理当前页面的所有埋点事件。
为了减少埋点对业务代码的影响,events.js
中每个埋点的设置都是一个方法,可以在这个方法中处理数据得到埋点需要上送的数据。
该埋点设置的方法,返回一个埋点需要上送的参数的对象。
// src/views/PageA/events.js
export default {
// 按事件类型管理
CLICK: {
back(ctx, data) {
let { param1, param2 } = data;
// ...处理传入的数据
return {
eventType: 'BUTTON',
eventValue: '返回',
elementId: 'pageA-返回',
// 需要上送的处理后的业务参数
customData: {
param1,
param2
}
};
}
}
}
复制代码
遵循使用简单的原则,调用埋点
// src/views/PageA/index.vue
this.$track('CLICK.back', data);
复制代码
实现上面的调用
- 使用
require.context()
聚合各个页面下的埋点设置。 - 聚合后的埋点设置按页面作为模块管理。
- 结合路由管理,获得当前页面的埋点配置模块名。
- 在
Vue.prototype
下新增一个$track()
方法。
// src/events/index.js
import router from '@/router';
const ctx = require.context('@/views', true, /events\.js/);
const configs = {};
ctx.keys().reduce((configs, path) => {
if (/\.\/(\w+?)\/events\.js/.test(path)) {
const moduleName = RegExp.$1; // 第一个子项
configs[moduleName] = resolveModule(moduleName, ctx(path));
}
return configs;
}, configs);
function resolveModule(moduleName, module) {
return Object.entries(module.default).reduce((all, [EVENT_TYPE, events]) => {
let eventtype = EVENT_TYPE.toLowerCase();
// 后面补充
});
}
export function track(eventPath, ...args) {
let event = configs;
let seg;
const segs = eventPath.split('.');
// 2段式 没有提供模块名,则需要去路由配置上取
if (segs.length === 2) {
const moduleName = router.currentRoute.meta?.eventModule;
if (!moduleName) {
throwError(`${eventPath} 没有在路由配置中设置"meta.eventModule" 或者配置成3段式`);
}
event = event[moduleName];
}
while ((seg = segs.shift())) event = event[seg];
if (!event) throwError(`${eventPath} 不存在`);
// 给event绑定当前调用环境
return event.call(this, ...args);
}
function throwError(err) {
throw Error(`[Track Error] ${err}`);
}
export default function install(Vue) {
Vue.prototype.$track = track;
}
复制代码
埋点设置支持对象形式
很多时候,可能不需要上送业务参数,写成一个对象更加简单。
{
CLICK: {
back: {
eventType: 'BUTTON',
eventValue: '返回',
elementId: 'pageA-返回',
}
}
}
复制代码
有时候只需要上送简单的业务字段,无需额外处理,也想使用对象的形式。
支持{{param1}}
模板语法,同vue-template用法。(param1
是埋点调用组件的属性)
{
CLICK: {
back: {
eventType: 'BUTTON',
eventValue: '返回',
elementId: 'pageA-返回',
customData: {
param1: '{{param1}}'
}
}
}
}
复制代码
将对象格式的埋点配置转成方法形式的
const templateRE = /\{\{(.+?)\}\}/g;
// 处理对象形式的埋点设置
function obj2fn(obj) {
return function() {
const that = this;
// 处理模板字符串
(function resolveObj(obj) {
Object.keys(obj).forEach(key => {
const val = obj[key];
// 解析模板字符串
if (typeof val === 'string' && templateRE.test(val)) {
obj[key] = val.replace(templateRE, (...match) => {
// js严格模式下无法执行with语法,以下是一种变通
return new Function(`with(this){return ${match[1]}}`).call(that);
});
}
// 递归处理
else if (isPlainObject(val)) resolve(val);
});
})(obj);
return obj;
};
}
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END