前言
前段时间公司有要做埋点的需求,于是想封装一个插件化的埋点工具,接着总结小程序端中的常用埋点吧,因为公司用的是uni-app所以就以uni-app为主可能有部分会和原生不一样!🐶
生命周期
class wxLog {
proxyApp (eventName,cb) {
let that = this;
const orgEvent = App;
App = function (value) {
let orgFun = value[eventName];
value[eventName] = function () {
cb.apply(that,[eventName,...arguments]);
orgFun.apply(this,arguments)
}
orgEvent.apply(this,arguments)
}
}
AppControl (eventName,value) {
let sendData = {
kind:'behavior',
type:'APPInit',
eventName:eventName,
time:new Date(),
}
// 发送逻辑忽略
}
init () {
this.proxyApp('onLaunch',this.AppControl);
this.proxyApp('onShow',this.AppControl);
this.proxyApp('onHide',this.AppControl);
}
}
路由
function getWxCurrentPage () {
var pageList = getCurrentPages();
var index = pageList.length -1;
var current = pageList[index];
if (current) {
return current.route
} else {
return ''
}
}
class wxLog {
constructor (option) {
this.isUniapp =option.isUniapp
}
setRoute (eventName,value) {
if (value && value.url) {
let currentPage = getWxCurrentPage();
let toPath = value.url;
let toRoute = getMiniPath(toPath);
let now = new Date().getTime();
let duration = now - this.currentTime;
this.currentTime = now;
let sendObj = {
kind:'behavior',
type:'pageSwitch',
currentPage,
toRoute,
eventName,
duration,
}
}
}
setRouteBack (eventName,value) {
if (value && value.delta) {
if (Object.prototype.toString.call(value.delta) === '[object Number]') {
let pageList = getCurrentPages();
let toPage = pageList[pageList.length-1-value.delta];
if (toPage && toPage.route) {
let currentPage = getWxCurrentPage();
let toPath = toPage.route;
let toRoute = getMiniPath(toPath);
let now = new Date().getTime();
let duration = now - this.currentTime;
this.currentTime = now;
let sendObj = {
kind:'behavior',
type:'pageSwitch',
currentPage,
toRoute,
eventName,
duration,
}
}
}
}
}
proxy (event,eventName,cb) {
let that = this;
let orgEvent = event[eventName];
event[eventName] = function () {
cb.apply(that,[eventName,...arguments])
orgEvent.apply(this,arguments)
}
}
init () {
if (this.isUniapp) {
this.proxy(uni,'navigateTo',this.setRoute);
this.proxy(uni,'redirectTo',this.setRoute);
this.proxy(uni,'reLaunch',this.setRoute);
this.proxy(uni,'navigateBack',this.setRouteBack);
} else {
this.proxy(wx,'navigateTo',this.setRoute);
this.proxy(wx,'redirectTo',this.setRoute);
this.proxy(wx,'reLaunch',this.setRoute);
this.proxy(wx,'navigateBack',this.setRouteBack);
}
}
}
HTTP
class wxLog {
requestControl (eventName,value) {
let that = this;
let sendData = {
kind:'httpRequest',
duration:'',
status:'',
requestUrl:'',
method:'',
body:'',
response:'',
time:getTime(),
location:getWxCurrentPage(),
responseHeader:'',
errMsg:'',
}
let requestTime = new Date().getDate()
let successFun = value.success;
let failFun = value.fail;
let sendType = value.sendType || ''
sendData.body = value.data;
sendData.method = value.method;
sendData.requestHeader = value.header;
sendData.requestUrl = value.url;
value.success = function (response) {
let responseTime = new Date().getDate()
sendData.response = response.data;
sendData.status = response.statusCode;
sendData.responseHeader = response.header;
sendData.errMsg = response.errMsg;
sendData.duration = responseTime - requestTime;
sendData.time = getTime();
if (!sendType) // 发送埋点
successFun.apply(this,arguments)
}
value.failFun = function (value) {
sendData.response = value;
sendData.status = 'fail';
if (!sendType) // 发送埋点
failFun.apply(this,arguments)
}
}
proxy (event,eventName,cb) {
let that = this;
let orgEvent = event[eventName];
event[eventName] = function () {
cb.apply(that,[eventName,...arguments])
orgEvent.apply(this,arguments)
}
}
init () {
this.proxy(wx,'request',this.requestControl);
}
}
JS报错
class wxLog {
constructor (option,_vue) {
this._vue = _vue;
}
proxyError () {
this._vue.config.errorHandler = (err,vm,info) => {
let sendData = {
kind:'stability',
type:err.name,
errorMessage:err.message,
time:getTime(),
location:getWxCurrentPage(),
errorStack:err.stack
}
};
}
init () {
this.proxyError()
}
}
点击事件
这里因为uni-app是通过一个__e的函数包装后调用的所以需要先判断是否是__e函数,在对其具体函数做重写
class wxLog {
proxyEvent () {
let that = this;
const oldComponent = Component;
Component = function (config) {
Object.keys(config.methods).forEach(methodName => {
if (methodName === "__e") {
that.proxyEventHandle(config.methods, methodName)
}
})
oldComponent.apply(this,arguments)
}
}
proxyEventHandle (methods,methodName) {
let oldMethod = methods[methodName];
let that = this;
methods[methodName] = function () {
let _vm = this.$vm;
let eventObj = arguments[0];
let type = eventObj['type'];
if (that.eventList.indexOf(type)!=-1) {
let target = eventObj.currentTarget || {};
let tapDomId = target.id?'#'+target.id:'';
let dataset = target.dataset || {};
let keys = Object.keys(that.eventController);
let sendData = {
kind:'event',
type:type,
dom:tapDomId,
data:'',
location:getWxCurrentPage(),
}
if (!!dataset.eventOpts && type) {
if (type == "tap") { //只记录点击事件
const event_opts = dataset.eventOpts;
if (Array.isArray(event_opts) && event_opts[0].length === 2) {
let eventFunc = [];
event_opts[0][1].forEach(event => {
eventFunc.push({
name: event[0],
params: event[1] || ''
})
})
sendData.data = eventFunc;
}
}
}
oldMethod.apply(this,arguments)
}
}
init () {
this.proxyEvent()
}
}