uniapp手动埋点
本文实现的是:手动埋点进入页面和出去页面事件向后端发送请求记录用户一些基础数据(包括设备信息,网络信息,以及页面停留时间,用户id,页面渲染性能等等,可以看下面的埋点方法里,没有的,需要什么可以自由添加什么)
看了很多文章都没有找到合适我的uniapp手动埋点(我的需求是进入页面和退出页面时监测页面情况,最终要打包成h5),看到了这个https://blog.youkuaiyun.com/qq_59747594/article/details/125583037(若侵权请联系删除)博主写的符合我想要的埋点,但是这个是基于跳转(uni.navigateTo、uni.redirectTo、uni.reLaunch、uni.switchTab、uni.navigateBack等)的封装来调用埋点函数的,我在使用的时候发现这样没法去监测页面左上角的返回和物理返回页面的情况,因此基于上述作者原方法的基础上运用了生命周期来调用埋点方法的方式来实现手动埋点
先写一个埋点js方法(这里我用的是上述作者写的方法,在原作者基础上做了小小的修改)
// 埋点通用接口
// triggerType: 必传 类型 entryStr(进入) || leaveStr(离开) || String:自定义事件描述
// pageUrl:非必传,页面路径,不穿默认获取当前路径
//再写一个触发事件
async function myMta(triggerType = "", pageUrl = "") {
console.log("埋点", triggerType, pageUrl);
let entryTime, leaveTime, stayTime, nowTime;
// entryTime 进入页面时间
// leaveTime 离开页面时间
// stayTime 停留时长
// nowTime 进行当前函数的时间
if (!triggerType) return;
if (triggerType == "entryStr") {
entryTime = new Date().getTime();
nowTime = new Date().getTime();
leaveTime = null;
uni.setStorageSync("entryTime", entryTime);
} else {
entryTime = uni.getStorageSync("entryTime");
leaveTime = new Date().getTime();
stayTime = leaveTime - entryTime;
nowTime = new Date().getTime();
}
//异步请求当前网络信息是wifi还是啥
uni.getNetworkType({
success: function (res) {
let networkType = res.networkType;
let token, openid, sysTemInfo;
try {
uni.getStorage({
key: "userInfo",
success: function (res) {
console.log(res, 34);
token = res.data.token;
openid = res.data.openId;
uni.getSystemInfo({
success: function (res) {
sysTemInfo = res;
const urlArgs = getCurrentPageUrlWithArgs(); //通过这个函数获取当前页面的信息 如果想返回更多自己去函数里面更改
console.log(leaveTime, "leaveTime");
var data = {
token: token,
openid: openid,
triggerType: triggerType,
networkType: networkType,
pageInfo: JSON.stringify({
pageUrl: pageUrl,
route: urlArgs.route,
params: urlArgs.options,
title: urlArgs.title,
}),
entryTime: toDateDetail(entryTime),
leaveTime: toDateDetail(leaveTime),
nowTime: toDateDetail(nowTime),
stayTime: stayTime,
sysTemInfo: JSON.stringify(sysTemInfo),
};
//只有离开页面时才把页面渲染时间这个字段传给后端
if (triggerType === "leaveStr") {
data.pageLoadTime = uni.getStorageSync("pageLoadTime");
}
var headers = {};
headers["X-Token"] = token;
console.log("mddata", data);
uni.request({
url: "https://lingzhuang.gengduoke.com/adminapi/customtrajectory/sav",
data: data,
header: headers,
method: "post",
success: (res) => {
// console.log('res', res)
},
fail: (err) => {
// console.log('err', err)
},
});
},
fail(error) {
sysTemInfo = "null";
},
});
},
fail(error) {
token = "null";
},
});
} catch (e) {}
},
});
}
// 获取当前页面链接和参数
function getCurrentPageUrlWithArgs() {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1]; //当前页面的全部信息
const route = currentPage.route; //当前路由的路径 pages/login/login
const options = currentPage.options; //url里面的参数json类型
const title = currentPage.$holder.navigationBarTitleText; //当前页面的navigationBarTitleText
// /拼接路由url字符串开始///
let urlWithArgs = `/${route}?`; //将url里面的参数拼接成字符串 /pages/login/login?a=1
for (let key in options) {
const value = options[key];
urlWithArgs += `${key}=${value}&`;
}
urlWithArgs = urlWithArgs.substring(0, urlWithArgs.length - 1);
// /拼接路由url字符串结束///
return {
options, //当前页面的参数
urlWithArgs, //当前页面的参数
route,
title,
};
}
function toDateDetail(number) {
if (!number) number = new Date();
// var n = number * 1000
var date = new Date(number);
var Y = date.getFullYear() + "-";
var M =
(date.getMonth() + 1 < 10
? "0" + (date.getMonth() + 1)
: date.getMonth() + 1) + "-";
var D = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
var h = date.getHours() < 10 ? "0" + date.getHours() : date.getHours();
var mm = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
var s = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
return Y + "" + M + "" + D + " " + h + ":" + mm + ":" + s;
}
/**
* appId -> 小程序ID 类型:String
* appToken -> 自定义 类型:String
* token -> 当前用户token 类型:String
* openid -> 当前用户openid 类型:String
* triggerType -> 事件类型 类型:String
* pageInfo { -> 当前页面信息 类型:Object
* pageUrl: -> 不带参数 类型:String
* url: -> 带参数 类型:String
* ...params -> 当前页面所有参数 类型:Object
* }
* entryTime -> 进入页面时间 类型:Number
* leaveTime -> 离开当前页面时间 类型:Number
* stayTime -> 停留时长 类型:Number 单位:ms
* sysTemInfo -> 设备信息 类型:Object
*/
export default {
myMta,
};
在写一个mixin
//引入上边写好的js文件
import Mta from "@/common/utils/trackingEvent/myMta.js";
export default {
data() {
return {
url: "", //跳转url
triggerType: "", //事件类型 进入、离开
loadStartTime: "", //页面加载开始时间
// loadEndTime: "", //页面加载完成时间
};
},
onLoad() {
this.entryTrack();
},
onReady() {
this.pageLoadTime();
},
onHide() {
this.leaveTrack();
},
onUnload() {
this.leaveTrack();
},
methods: {
/**
* 进入页面时埋点
*/
entryTrack() {
console.log("-------------onLoad----------------");
//这里记录进入当前页面的onload的时间(我用的dayjs工具库,你也可以用js的Date对象来换取当前时间)
let loadStartTime = this.$dayjs().format("YYYY-MM-DD HH:mm:ss:SSS");
let url = getCurrentPages()[getCurrentPages().length - 1].route;
this.url = url;
this.triggerType = "entryStr";
this.loadStartTime = loadStartTime;
Mta.myMta("entryStr", this.url);
},
/**
* 缓存页面加载时间
*/
pageLoadTime() {
console.log("-------------onReady----------------");
//这里记录进入当前页面的onready的时间(我用的dayjs工具库,你也可以用js的Date对象来换取当前时间),
let loadEndTime = this.$dayjs().format("YYYY-MM-DD HH:mm:ss:SSS");
//计算出从进入页面的onload到onready所用的时间(毫秒),用来记录页面渲染用的时间
let pageLoadTime = this.$dayjs(loadEndTime).diff(
this.$dayjs(this.loadStartTime),
"millisecond"
);
//将计算出的时间缓存到storage中
uni.setStorageSync("pageLoadTime", pageLoadTime);
},
/**
* 离开页面时埋点
*/
leaveTrack() {
//这里做这个判断主要是防止页面一直返回时重复调用离开页面的埋点方法
if (this.triggerType === "leaveStr") return;
this.triggerType = "leaveStr";
Mta.myMta("leaveStr", this.url);
},
},
};
将上面的mixin文件挂到全局上的(在main.js里引入)
//这个是我上面写得minxin文件
import trackingEvent from "@/common/mixins/trackingEvent.js"; //配合埋点的mixin
Vue.mixin(trackingEvent);
//我把dayjs这日期库下载到了本地引入,并且挂在了全局上,因此在上述的mixin文件里可以用this.$dayjs形式访问(还是那句话,你不用也行,用js的Date也一样)
import dayjs from "@/common/utils/dayjs.js";
Vue.prototype.$dayjs = dayjs;
例子,我这里有A、B、C三个页面
综上所述
1.可以看出来过程是A进入页面(触发A的onload)=》跳转到B页面(触发A的onhide、B的onload)=》跳转到C页面(触发B的onhide、C的onload)=》返回到B页面(触发C的onunload)