Authored by huzhiming

feat(数据埋点): 添加公共数据埋点代码

/* eslint-disable */
/*
* @ description: 埋点上报系统,包含曝光
* @ author: huzhiming
* @ date: 2019-12-09 15:00:27
* @ version: v1.0.0
* 调用示例:
import trackEventMixins from '@/pages/trackEventMixins'
mixins: [trackEventMixins],
*/
import { debounce, throttle, get } from 'lodash';
let currentList = []; // 定义曝光记录,防止重复曝光
let offsetTop = 0; // 距离视窗顶部距离
let vm = null;
export default {
data () {
return {};
},
created () {
vm = this; // 指令依赖vue实例
},
mounted () {},
activated () {
if (this.$refs.exposureRef) {
this.$refs.exposureRef.forEach((element, index) => {
element.dataset.trackid = `t_${index}`
element.dataset.index = index
});
this.$nextTick(() => {
window.addEventListener('scroll', debounce(throttle(this.handleScroll, 500), 500));
this.handleScroll(); // 首屏触发 曝光上报
});
}
/* 如果实例计算属性有此对象,则进行页面曝光上报 */
if (this.pageExposure && Object.keys(this.pageExposure).length > 0) {
this.$store.dispatch('reportYas', this.pageExposure);
}
},
deactivated () {
window.removeEventListener('scroll', null);
},
// beforeRouteEnter(to, from, next) {},
// beforeRouteUpdate(to, from, next) {},
// beforeRouteLeave(to, from, next) {},
destroyed () {
window.removeEventListener('scroll', null);
},
methods: {
handleScroll () {
let prevTop = offsetTop;
let direction = 'up';
let oldList = currentList.map((el) => ({
id: el.id,
visible: el.visible,
index: el.index
}));
const viewPortHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
let exposureRef = this.$refs.exposureRef
currentList = exposureRef.filter((el, index) => {
const Rect = el.getBoundingClientRect();
const top = el.getBoundingClientRect().top;
const elHeight = Rect.height;
const isInviewport = (top > 0 || top + elHeight > 0) ? top <= viewPortHeight : false; // 垂直方向 是否在视窗内
if (index === 0) {
offsetTop = top;
}
el.dataset.visible = isInviewport;
// console.log(`窗口宽度:${viewPortHeight},元素距离可视基准线top值:${top},是否在可视区域内:${top + elHeight < 0 ? false : top <= viewPortHeight}`);
return isInviewport;
});
currentList = currentList.map(el => ({
id: el.dataset.trackid,
visible: el.dataset.visible,
index: Number(el.dataset.index),
exposure: el.YAS_EXPOSURE_DATA // 注意:数据来源于 指令绑定 el.exposure = xxx
}));
// console.log('%c上次值:\n', 'color:#f00;', JSON.stringify(oldList), 'length', oldList.length);
// console.log('%c当前值:\n', 'color:#f00;', JSON.stringify(currentList), 'length', currentList.length);
// 计算滚动方向
if (prevTop!=0) {
if (prevTop >= offsetTop) {
direction = 'up'
} else {
direction = 'down'
}
}
// console.log('滚动方向:', direction);
// 防止重复上报逻辑
let newAddItemList = [];
let _tmp = currentList;
if (direction == 'up') {
// 保留结尾
let endIndex = 0;
if (oldList.length>0) {
endIndex = _tmp.findIndex(el=>{
return el.id === oldList[oldList.length - 1].id
})
endIndex+=1
}
newAddItemList = _tmp.slice(endIndex);
} else {
// 保留开头
let endIndex = 0;
if (oldList.length > 0) {
endIndex = _tmp.findIndex(el => {
return el.id == oldList[0].id
})
}
newAddItemList = _tmp.slice(0, endIndex)
}
// console.log('%c新加入元素节点:\n', 'color:#f00;', JSON.stringify(newAddItemList), currentList.length == oldList.length);
let reportList = newAddItemList.filter(el => el.visible == 'true'); // 筛选出可见的元素组成新集合,需要上报的数据集合
console.log('%c筛选出可见的元素组成新集合,进行曝光事件上报,需要上报的数据元素为:\n', 'color:#f00;', JSON.stringify(reportList))
if (reportList.length > 0) {
reportList = reportList.map(el => el.exposure)
this.dispatchExposure(reportList);
}
},
// 触发曝光事件 数据上报
dispatchExposure (reportList) {
// var index = Number('expose_7'.match(/expose\_(\S*)/i)[1])
console.log(JSON.stringify(reportList));
},
// 触发点击事件 数据上报
dispatchClick (target) {
if (target.YAS_CLICK_DATA) {
console.log('我只负责点击事件上报:', JSON.stringify(target.YAS_CLICK_DATA));
// this.$store.dispatch('reportYas', this[target.YAS_CLICK_DATA]);
}
}
},
computed: {},
watch: {},
components: {},
directives: {
// 坑位点击 上报数据绑定
trackClick: {
bind(el, binding) {
const { value } = binding;
if (value.props && value.props != '' && typeof value.index !== 'number') {
el.YAS_CLICK_DATA = vm[value.props]
} else {
el.YAS_CLICK_DATA = vm[value.props][value.index]
}
// 加入防抖和节流
el.addEventListener('click', debounce(throttle(vm.dispatchClick.bind(vm, el), 500), 200), false);
},
unbind (el, binding){
el.removeEventListener('click', null);
}
},
// 坑位曝光事件 上报数据绑定
trackExposure: {
bind (el, binding) {
const { value } = binding;
if (value.props && value.props!='') {
el.YAS_EXPOSURE_DATA = vm[value.props][value.index]
}
}
}
}
};
... ...
... ... @@ -76,35 +76,7 @@ const mixins = {
computed: {},
watch: {},
components: {},
directives: {
expose: {
// 指令的定义
inserted: function (el,binding,vnode,oldVnode) {
console.log('inserted', el.getBoundingClientRect());
},
bind: function (el,binding,vnode,oldVnode) {
console.log('bind', el);
// var s = JSON.stringify
// el.innerHTML =
// 'name: ' + s(binding.name) + '<br>' +
// 'value: ' + s(binding.value) + '<br>' +
// 'expression: ' + s(binding.expression) + '<br>' +
// 'argument: ' + s(binding.arg) + '<br>' +
// 'modifiers: ' + s(binding.modifiers) + '<br>' +
// 'vnode keys: ' + Object.keys(vnode).join(', ')
},
update: function (el,binding,vnode,oldVnode) {
console.log('update', el);
},
componentUpdated: function (el,binding,vnode,oldVnode) {
console.log('componentUpdated', el);
},
unbind: function (el,binding,vnode,oldVnode) {
console.log('unbind', el);
},
}
}
directives: {}
}
export default {
... ...