本博文实现了uniapp的数据统计埋点的封装,可以自动统计页面的PV, UV,页面停留时长,不需要在每个页面的生命周期写统计(tabBar 的页面除外,tabBar 页面需要添加自定义事件)
使用说明:
1.需要在APP.vue 初始化进入时间缓存 ,示例:
onLaunch: function() {
if (!uni.getStorageSync('entryTime')) {
uni.setStorageSync('entryTime', new Date().getTime())
}
},
2.在 tabBar 页面加载和离开的生命周期手动统计
this.$common.Init.call(this);
// 统计自定义事件触发埋点
this.myMta('show')
3.修改mtaUrl 和 appId。
实现思路:重写unaipp的路由,在调用路由跳转的时候触发页面PV,UV,停留时长的信息统计,因为tabBar 不会触发路由跳转的API,所以需要在其中的页面用自定义事件手动添加上。
下面上代码:
main.js
import nav from "@/util/navRoute.js";
Vue.prototype.$navTo = nav;
页面跳转统一用我封装的API,示例:
this.$navTo.navigateTo({
url: '/pages/test/test'
})
common.js
import Mta from "@/util/myMta.js";
function Init(e) {
this.myMta = (...ev) => {
Mta.myMta(...ev)
}
}
navRoute.js
import Mta from "@/util/myMta.js";
var nav = {
navigateTo: ({
url
}) => {
var link = getCurrentPages()[getCurrentPages().length - 1].route;
Mta.myMta('leaveStr', link)
console.log('navigateTo', link,'-',url)
uni.navigateTo({
url: url,
success: function(res) {
Mta.myMta('entryStr', url)
}
});
},
redirectTo: ({
url
}) => {
var link = getCurrentPages()[getCurrentPages().length - 1].route;
Mta.myMta('leaveStr', link)
console.log('redirectTo', link,'-',url)
uni.redirectTo({
url: url,
success: function(res) {
Mta.myMta('entryStr', url)
}
});
},
reLaunch: ({
url
}) => {
var link = getCurrentPages()[getCurrentPages().length - 1].route;
Mta.myMta('leaveStr', link)
console.log('reLaunch', link,'-',url)
uni.reLaunch({
url: url,
success: function(res) {
Mta.myMta('entryStr', url)
}
});
},
switchTab: ({
url
}) => {
var link = getCurrentPages()[getCurrentPages().length - 1].route;
Mta.myMta('leaveStr', link)
console.log('switchTab', link,'-',url)
uni.switchTab({
url: url,
success: function(res) {
Mta.myMta('entryStr', url)
}
});
},
navigateBack: ({
num
}) => {
var link = getCurrentPages()[getCurrentPages().length - 1].route;
Mta.myMta('leaveStr', link)
console.log('navigateBack', link,'-',num)
uni.navigateBack({
delta: num
});
}
}
export default { ...nav
};
myMta.js
const mtaUrl = 'https://cxxx.cn/commonapi/system/saveRecordLog'
const appId = 'test';
// 埋点通用接口
// triggerType: 必传 类型 entryStr(进入) || leaveStr(离开) || String:自定义事件描述
// pageUrl:非必传,页面路径,不穿默认获取当前路径
async function myMta(triggerType = "", pageUrl = '') {
console.log('埋点', triggerType, pageUrl)
let entryTime, leaveTime,stayTime,sceneType,params;
// entryTime 进入页面时间
// leaveTime 离开页面时间
// stayTime 停留时长
// sceneType 渠道类型 1 线上渠道用户数 2 线下渠道用户数 3 非扫描二维码用户数
if (!triggerType) return
if (triggerType == 'entryStr') {
entryTime = new Date().getTime();
leaveTime = null;
uni.setStorageSync('entryTime',entryTime)
} else {
entryTime = uni.getStorageSync('entryTime');
leaveTime = new Date().getTime();
stayTime = leaveTime-entryTime;
}
// 获取页面路径及参数
const urlArgs = getCurrentPageUrlWithArgs();
if (!pageUrl) {
leaveTime = new Date().getTime();
if (urlArgs.indexOf("?") != -1) {
let url, result, reqDataString;
pageUrl = urlArgs.split("?")[0];
url = urlArgs.split("?")[1];
result = url.replace(/&/g, '","').replace(/=/g, '":"');
reqDataString = '{"' + result + '"}';
params = JSON.parse(reqDataString);
} else {
pageUrl = urlArgs;
}
}
wx.getNetworkType({
success: function(res) {
let networkType = res.networkType;
let token,openid;
try {
let scene = JSON.parse(wx.getStorageSync("userInfo")).scene;
token = JSON.parse(wx.getStorageSync("userToken")).tk || "暂无:token";
if (!scene) {
sceneType = 3
} else {
sceneType = (scene !== '02be37d9cfbf45f9aa1013180c80bfe0') ? 1 : 2;
}
} catch (e) {}
var data = {
token: token,
openid: token,
scene: sceneType,
triggerType: triggerType,
networkType: networkType,
pageInfo: {
pageUrl: pageUrl,
url: urlArgs,
...params,
},
entryTime: toDateDetail(entryTime),
leaveTime: toDateDetail(leaveTime),
stayTime: stayTime,
sysTemInfo: wx.getStorageSync("sysTemInfo"),
}
wx.request({
url: mtaUrl,
data: data,
method: "POST",
header: {
"content-type": "application/json",
"appId": appId,
// "appId": "const_wywplus",
"appToken": "mkgame?" + chars(),
},
success(res) {
if (res.data.code == 200) {} else {
console.error('请求失败')
}
},
fail: (ret) => {
console.error(ret);
}
})
}
})
}
// 获取当前页面链接和参数
function getCurrentPageUrlWithArgs() {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
const url = currentPage.route;
const options = currentPage.options;
let urlWithArgs = `/${url}?`;
for (let key in options) {
const value = options[key];
urlWithArgs += `${key}=${value}&`;
}
urlWithArgs = urlWithArgs.substring(0, urlWithArgs.length - 1);
return urlWithArgs;
}
function chars() {
let chars = "0123456789";
/****默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/
let maxPos = chars.length;
let code = "";
for (let i = 0; i < 6; i++) {
code += chars.charAt(Math.floor(Math.random() * maxPos));
}
return code;
}
function toDateDetail(number) {
if(!number)return '';
// 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
};