vue-auto-track
Version:
auto tracking for vue
249 lines (247 loc) • 6.87 kB
JavaScript
import Exposure from "vue-auto-track/src/untils/exposure";
import {
// PageLifeCycle,
AppLifeCycle,
VueLifeCycle,
} from "vue-auto-track/src/untils/lifecycle";
import initNativeInfo, {
thirdTrack,
} from "vue-auto-track/src/untils/get-upload";
import { getUuid } from "./untils/tools.js";
import { MAX_LOCALSTORAGE, ENV_WX } from "vue-auto-track/src/untils/global";
const observesPg = [];
const observesCp = [];
let pageConfig = {};
let trackFn = null;
let methodsUid = {};
let currentPage = null;
let VueComponent = null;
let pageInTime = 0;
let pageOutTime = 0;
let pages = [];
let trigTrackTimer = null;
let linkId = "";
const trackMixin = {
// ...PageLifeCycle,
...AppLifeCycle,
...VueLifeCycle,
data() {
return {};
},
onLaunch() {
linkId = getUuid();
},
onShow() {
pageInTime = new Date().getTime();
pageOutTime = 0;
if (this.mpType) {
trackFn("page_in", {}, "page");
}
if (!pageConfig[currentPage]) {
return;
}
pageConfig[currentPage].selectorsPg.forEach((selector) => {
const observe = new Exposure(this);
observe.startObserver(selector.selector, (res) => {
if (res.intersectionRatio === 1) {
const pros = Object.keys(this);
let trackData = {};
for (let pro of pros) {
if (typeof this[pro] === `function`) {
continue;
} else {
if (/^_|\$/.test(pro)) {
continue;
}
if (~[`mpHost`, `mpType`].indexOf(pro)) {
continue;
}
trackData[pro] = this[pro];
}
}
trackFn(`exposure`, trackData);
}
});
observesPg.push(observe);
});
},
onUnload() {
methodsUid = {};
while (observesCp.length) {
observesCp.shift().disconnect();
}
},
onHide() {
methodsUid = {};
if (!this.mpType) {
// 应用隐藏到后台
trackFn(`quit`, {}, "aplication");
} else {
pageOutTime = new Date().getTime();
trackFn("page_out", {}, "page");
}
while (observesPg.length) {
observesPg.shift().disconnect();
}
},
mounted() {
if (this.mpType === `page`) {
return;
}
if (!pageConfig[currentPage]) {
return;
}
pageConfig[currentPage].selectorsCp.forEach((selector) => {
const observe = new Exposure(this);
observe.startObserver(selector.selector, (res) => {
if (res.intersectionRatio === 1) {
const pros = Object.keys(this);
let trackData = {};
for (let pro of pros) {
if (typeof this[pro] === `function`) {
continue;
} else {
if (/^_|\$/.test(pro)) {
continue;
}
if (~[`mpHost`, `mpType`].indexOf(pro)) {
continue;
}
trackData[pro] = this[pro];
}
}
trackFn(`exposure`, trackData);
}
});
observesCp.push(observe);
});
},
created() {
if (this.mpType === `page`) {
pages = getCurrentPages();
currentPage = this.__route__;
}
let trackFns = [];
let trackData = {};
const pros = Object.keys(this);
for (let pro of pros) {
if (typeof this[pro] === `function`) {
if (/^_|\$/.test(pro)) {
continue;
}
if (trackFns.indexOf(pro) !== -1) {
throw new Error(`实例中存在重名的方法--${pro}`);
}
if (methodsUid[pro]) {
if (
methodsUid[pro] !==
trackFns.sort().toString() + this.$options.name
) {
console.warn(
`页面结构中不同组件存在同名方法${pro},请对同名方法进行区分,否则无法进行埋点分析`
);
}
} else {
methodsUid[pro] = trackFns.sort().toString() + this.$options.name;
}
trackFns.push(pro);
} else {
if (/^_|\$/.test(pro)) {
continue;
}
if (~[`mpHost`, `mpType`].indexOf(pro)) {
continue;
}
trackData[pro] = ``;
}
}
for (let fn of trackFns) {
const newFn = this[fn];
let pageEvent = [];
let contentEvent = [];
if (pageConfig[currentPage]) {
pageEvent = pageConfig[currentPage].pageEvent || [];
contentEvent = pageConfig[currentPage].contentEvent || [];
}
this[fn] = (arg1, arg2, arg3, arg4, arg5) => {
if (arguments.length > 5) {
throw new Error(`方法${fn}的入参数量不能大于5`);
}
if (fn.indexOf("track") !== -1) {
if (!trigTrackTimer) {
if (arg1 && arg2 && arg3) {
trackFn(fn, { arg1, arg2, arg3 });
} else if (arg1 && arg2) {
trackFn(fn, { arg1, arg2 });
} else {
trackFn(fn, { arg1 });
}
} else {
clearTimeout(trigTrackTimer);
}
trigTrackTimer = setTimeout(() => {
trigTrackTimer = null;
}, 300);
}
return newFn(arg1, arg2, arg3, arg4, arg5);
};
}
},
};
export default {
install(Vue, options) {
// let init = Vue.prototype._init
// // init.call(Vue)
// Vue.prototype._init = function (op) {
// console.log(1111,op)
// init.call(this, op)
// }
if (!options.env || !options.upload) {
throw new Error(`请配置环境以及上传埋点数据的请求`);
}
if (options.env == ENV_WX) {
if (options.size >= MAX_LOCALSTORAGE) {
throw new Error(`上传触发最大存储限制不能超过${MAX_LOCALSTORAGE}字节`);
}
}
if (options.upload.then) {
throw new Error(`请求必须配置为promise对象`);
}
pageConfig = options.pageConfig || {};
VueComponent = Vue;
initNativeInfo(options.env);
let { plugins = [] } = options;
trackFn = (eventCode, data, eventType = "component") => {
let page = (pages.length && pages[pages.length - 1].route) || "";
// let from_page =
// (pages.length &&
// pages[pages.length - 1] &&
// pages[pages.length - 1].route) ||
// "";
plugins.length &&
options.plugins.forEach((item) =>
item(eventCode, {
// from_page,
pageInTime: pageInTime + "",
pageOutTime: pageOutTime + "",
pageId: page,
...data,
})
);
thirdTrack(
eventCode,
{
// from_page,
eventType,
pageInTime: pageInTime + "",
pageOutTime: pageOutTime + "",
pageId: page,
linkId,
...data,
},
options
);
};
Vue.mixin(trackMixin);
},
};