简单来说,就是当引入无痕埋点的库以后
用户在浏览器里所有行为和操作都会被自动记录下来
并将信息发送到后端进行统计和分析
传统的埋点形式,都是手动埋点
在指定的元素上绑定事件
将用户行为信息发送到服务端进行统计
假设如果有一万个点需要前端狗去埋,惊喜不惊喜,意外不意外
提高工作效率,解放双手
屌丝的双手得到解放以后
就有更多的时间拿双手来取悦自己
嘻嘻
原理很简单,这里只讲click的无痕埋点原理
当用户点击了页面上某一个元素
我们要把当前元素到body之间整个dom的路径记录下来,作为这个元素的唯一标识,我们称之为domPath
这个domPath不仅是这个元素唯一标识
还可以通过document.querySelector(domPath)去唯一选择和定位到这个元素
当用户点击一次这个元素,就会将埋点数据上传到服务器
服务器上这个domPath对应的统计数据加一
document.body.addEventListener('click', (event) => {
const eventFix = getEvent(event);
if (!eventFix) {
return;
}
this._handleEvent(eventFix);
}, false)
首先在document的body上监听和绑定全局click事件,捕获用户所有的点击事件。
const getDomPath = (element, useClass = false) => {
if (!(element instanceof htmlElement)) {
console.warn('input is not a HTML element!');
return '';
}
let domPath = [];
let elem = element;
while (elem) {
let domDesc = getDomDesc(elem, useClass);
if (!domDesc) {
break;
}
domPath.unshift(domDesc);
if (querySelector(domPath.join('>')) === element || domDesc.indexOf('body') >= 0) {
break;
}
domPath.shift();
const children = elem.parentNode.children;
if (children.length > 1) {
for (let i = 0; i < children.length; i++) {
if (children[i] === elem) {
domDesc += `:nth-child(${i + 1})`;
break;
}
}
}
domPath.unshift(domDesc);
if (querySelector(domPath.join('>')) === element) {
break;
}
elem = elem.parentNode;
}
return domPath.join('>');
}
这段代码是关键,获取元素唯一标识domPath
getDomPath函数传入的是用户点击事件的target对象: getDomPath(event.target)。
主要思路是找到当前元素event.target
然后不断的去循环找它的父节点parentNode
将父节点的tagName当做domPath路径上的节点
如果当前元素有id,那就取消所有路径的循环,直接讲id赋值给domPath
const children = elem.parentNode.children;
if (children.length > 1) {
for (let i = 0; i < children.length; i++) {
if (children[i] === elem) {
domDesc += `:nth-child(${i + 1})`;
break;
}
}
}
domPath.unshift(domDesc);
getDomPath函数中的这段代码
意思是在同一级上出现了多个相同tagName元素
那我们要定位到这个event.target这个元素在这一级里的第几个
假设这个div是同一级的第三个,那返回的就是div:nth-child(3)
这样就可以在document.querySelector(domPath)里唯一定位到这个元素
_handleEvent(event) {
const domPath = getDomPath(event.target);
const rect = getBoundingClientRect(event.target);
if (rect.width == 0 || rect.height == 0) {
return;
}
let t = document.documentElement || document.body.parentNode;
const scrollX = (t && typeof t.scrollLeft == 'number' ? t : document.body).scrollLeft;
const scrollY = (t && typeof t.scrollTop == 'number' ? t : document.body).scrollTop;
const pageX = event.pageX || event.clientX + scrollX;
const pageY = event.pageY || event.clientY + scrollY;
const data = {
domPath: encodeURIComponent(domPath),
trackingType: event.type,
offsetX: ((pageX - rect.left - scrollX) / rect.width).toFixed(6),
offsetY: ((pageY - rect.top - scrollY) / rect.height).toFixed(6),
};
this.send(data);
}
这段代码就是得到用户点击某个元素的相对位置的横向位置和竖向位置比例
得到这个位置的值,就可以反向从埋点数据中得到用户点击元素的具体位置
因为是个比例值,所以在反向推导中还能自适应页面大小的改变
send(data = {}) {
const image = new Image(1, 1);
image.onload = function () {
image = null;
};
image.src = `/?${stringify(data)}`;
}
得到了用户点击的位置信息和唯一标识domPath
就可以将数据发送到服务端进行统计了
用image的src,将数据进行传输
用image的src有个好处就是轻量,并且还支持跨域
打点基本上都用的这个方法进行发送数据
作者:第一名的小蝌蚪
微信公众号:前端屌丝
github: https://github.com/airuikun/blog
在线上项目中,需要统计产品中用户行为和使用情况,从而可以从用户和产品的角度去了解用户群体,从而升级和迭代产品,使其更加贴近用户。用户行为数据可以通过前端数据监控的方式获得,除此之外,前端还需要实现性能监控和异常监控
埋点方案的确定,业界的埋点方案主要分为以下三类:代码埋点:在需要埋点的节点调用接口,携带数据上传。如百度统计等;可视化埋点:使用可视化工具进行配置化的埋点,即所谓的「无痕埋点」
最近有一个工作需求是曝光埋点,让我得以有机会接触相关的东西。之前实习时没有做过这方面的需求,个人项目更是和埋点扯不上关系。以至于上周开会讨论时听到“埋点”这个词就怂了。
定义数据埋点及其交接主要分为四个部分,梳理数据需求—定义数据指标—埋点整理—文档输出——埋点验收,前两个步骤在上文中已经详细描述过方法,本文不再赘述。本文较为简洁,整理了梳理埋点的方法和与开发交接的方法
通过可视化交互的手段,代替代码埋点。将业务代码和埋点代码分离,提供一个可视化交互的页面,输入为业务代码,通过这个可视化系统,可以在业务代码中自定义的增加埋点事件等等
开发者有时会面临上线的生产环境包出现了异常:bug: ,在长期生产bug并修复bug的循环中总结出一下几个痛点:无法快速定位到发生错误的代码位置,因为脚手架构建时会用webapck自动帮我们压缩代码
前端埋点sdk的方案十分成熟,之前用的都是公司内部统一的埋点产品,从前端埋点和数据上报后的可视化查询全链路打通。但是在最近的一个私有化项目中就遇到了问题,因为服务都是在客户自己申请的服务器上的,需要将埋点数据存放到自己的数据库中
如何在 Vue 中对每个点击事件插入一个函数?由于 .vue 文件是将 <template>、<script> 和 <style> 分开进行单独解析,所以不能通过 babel 将监听函数准确解析出来
在动手实现之前,首先脑子里要有一个整体脉络,明白搭建前端监控具体的流程步骤有哪些。因为前端监控系统实际上是一个完整的全栈项目,而并不仅仅是前端,甚至主要的实现都是围绕在数据方面的。
这篇文章主要讲如何根据注释,通过babel插件自动地,给相应函数插入埋点代码,在实现埋点逻辑和业务逻辑分离的基础上,配置更加灵活
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!