「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战」
TIP 👉 休言女子非英物,夜夜龙泉壁上鸣。——秋瑾《鹧鸪天·祖国沉沦感不禁》
前言
数据埋点方案、监控方案
代码埋点
代码埋点是最灵活,同时也是最耗时的一种方式。
一般大厂内部会封装自己的一套埋点上报的npm包, 提供给各业务线使用。
一般我们需要上报什么信息呢?
-
埋点的标识信息, 比如eventId, eventType
-
业务自定义的信息, 比如教育行业, 点击一个按钮, 我们要上报用户点击的是哪个年级
-
通用的设备信息, 比如用户的userId, useragent, deviceId, timestamp, locationUrl等等
一般怎么上报?
-
实时上报, 业务方调用发送埋点的api后, 立即发出上报请求
-
延时上报, sdk内部收集业务方要上报的信息, 在浏览器空闲时间或者页面卸载前统一上报,上报失败会做补偿措施。
无埋点
概念
无埋点并不是真正的字面意思,其真实含义其实是,不需要研发去手动埋点。
一般会有一个 sdk 封装好各种逻辑, 然后业务方直接引用即可。
sdk中做的事情一般是监听所有页面事件, 上报所有点击事件以及对应的事件所在的元素,然后通过后台去分析这些数据。
业界有GrowingIO, 神策, 诸葛IO, Heap, Mixpanel等等商业产品
实现
- 监听window元素
window.addEventListener("click", function(event){
let e = window.event || event;
let target = e.srcElement || e.target;
}, false);
- 获取元素唯一标识 xPath
function getXPath(element) {
// 如果元素有id属性,直接返回//*[@id="xPath"]
if (element.id) {
return '//*[@id=\"' + element.id + '\"]';
}
// 向上查找到body,结束查找, 返回结果
if (element == document.body) {
return '/html/' + element.tagName.toLowerCase();
}
let currentIndex = 1, // 默认第一个元素的索引为1
siblings = element.parentNode.childNodes;
for (let sibling of siblings) {
if (sibling == element) {
// 确定了当前元素在兄弟节点中的索引后, 向上查找
return getXPath(element.parentNode) + '/' + element.tagName.toLowerCase() + '[' + (currentIndex) +
']';
} else if (sibling.nodeType == 1 && sibling.tagName == element.tagName) {
// 继续寻找当前元素在兄弟节点中的索引
currentIndex++;
}
}
};
获取元素的位置
function getOffset(event) {
const rect = getBoundingClientRect(event.target);
if (rect.width == 0 || rect.height == 0) {
return;
}
let doc = document.documentElement || document.body.parentNode;
const scrollX = doc.scrollLeft;
const scrollY = doc.scrollTop;
const pageX = event.pageX || event.clientX + scrollX;
const pageY = event.pageY || event.clientY + scrollY;
const data = {
offsetX: ((pageX - rect.left - scrollX) / rect.width).toFixed(4),
offsetY: ((pageY - rect.top - scrollY) / rect.height).toFixed(4),
};
return data;
}
上报
window.addEventListener("click", function(event){
const e = window.event || event;
const target = e.srcElement || e.target;
const xPath = getXPath(target);
const offsetData = getOffset(event);
report({ xPath, ...offsetData});
}, false);