小蝌蚪传记:200行代码实现前端无痕埋点

灰色的天javascript

妳的脸前端

说分手的语气斩钉截铁java

小蝌蚪:“能不走吗”git

女神:“不能”github

小蝌蚪:“那个男人有什么好”算法

女神:“他说话好听,长得帅,还有钱”后端

小蝌蚪:“我没房没车没存款,但我有一颗爱妳的心”跨域

高富帅出现:“我有房有车有存款,我也有一颗爱她的心”浏览器

小蝌蚪:“我能跑十千米去为她买宵夜”服务器

高富帅:“我开兰博基尼去为她买宵夜”

小蝌蚪:“我一分钟能敲5000行代码”

高富帅:“大家公司的老板,是我爸”

小蝌蚪:“这。。。”

在金钱力量面前,一切言语都显得那么苍白无力

小蝌蚪跪在地上,望着高富帅远去的尾灯,消失在地平线

失恋第三十天,小蝌蚪上山拜佛

小蝌蚪:“伟大的佛,为什么我感情如此失败”

佛曰:“由于你不够渣,一次只爱一我的,下次同时爱一百个试试?”

小蝌蚪如有所悟

小蝌蚪:“伟大的佛,那我如何才能成为江湖第一的渣男”

佛说:“想要成为顶级渣男,你要闯过三关”

佛:“第一关咱们称之为<富婆>”

佛:“一位顶级渣男,他须要有雄厚的资金来源,才能浪迹天涯,而富婆是这资金流的关键”

第一关<富婆>

获得佛主的指点,小蝌蚪来到国际大酒店

楼顶正举行富婆八十大寿生日宴

富婆坐在轮椅上,望着舞池里的妹纸

满眼都是本身十八岁的样子

小蝌蚪出现:“女士,您好,我叫小蝌蚪”

富婆:“有何贵干”

小蝌蚪:“我想要获得妳的包养”

富婆的假牙差点从嘴里喷了出来

富婆:“个人包养,不是你想要,想要就能要”

小蝌蚪就地表演了一段舌头碎大石

富婆压制住心里的狂喜,说道:“这还不够,还差了点”

小蝌蚪:“我一分钟能敲5000行代码,手速奇快”

富婆大惊:“你就是我惟一的真爱~!”

第二关<渣女>

成功拿下富婆后,来到第二关

佛曰:“你须要撩到一个名叫 '夜魔' 的顶级渣女,经过她身上的《绝世婊技》,你才能悟出传说中的《渣男心经》”

夜魔常年混迹于夜店

斡旋在多名富二代之间

夜魔的座右铭:“肾走多了,才明白走心的难得”

“渣男收割机”、“夜店王中王”、“叱咤级渣皇”

都是她曾用的小名

一位被她玩死的富二代

去世前曾留下遗言:

别爱上她,相信我

你只是寂寞的晚上

她想要缠绵的

小玩具

夜魔位列年度渣女榜榜首

小蝌蚪的任务,猎杀夜魔

凌晨一点,夜店

小蝌蚪:“小姐姐,您好,我叫小蝌蚪”

夜魔爱搭不理

鲁迅说过:“在金钱面前,一切渣女都是纸老虎”

小蝌蚪故意不经意间露出兰博基尼车钥匙(富婆八十大寿赠)

夜魔大喜:“哥哥,请坐!”

夜魔:“哥哥想喝点什么”

小蝌蚪:“想喝点妳的酒窝”

面对搭讪,夜魔故做脸红,伪装羞涩

让你以为她是一个清纯走心的小姐姐

夜魔:“我看哥哥挺有钱,哥哥职业是什么”

小蝌蚪:“个人职业是职业渣男”

一个低端富二代都是炫耀本身多有钱,爸爸多厉害

但一个顶级富二代,历来都是说本身是渣男

夜魔:“哥哥有喜欢的人吗”

小蝌蚪:“有,她在别人的床上”

小蝌蚪开始打感情牌,宣扬本身受过情伤

唤母爱,博同情

夜魔:“哥哥来找我什么事?”

小蝌蚪:“想借用妳的美色和媚术,帮我攻破一个男人”

夜魔:“谁?”

小蝌蚪:“我”

这是一个调情套路

面对渣女,你要表现的比她更渣

妳渣任妳渣,反正都没我渣

小蝌蚪再也不周旋,直接强攻

小蝌蚪:“明人不说暗话,我想和妳结婚”

夜魔是远近闻名的渣女,男人们只想和她暧昧

面对突如其来的‘结婚’,开始手无足措

小蝌蚪抓住时机,放大招

谈笑间侧露价值180万的金表(富婆八十大寿赠)

夜魔大惊

菊花一紧,虎躯一震

无数道圣光冲击她的天灵盖

夜魔热泪盈眶

满意的点了点头

酒后三巡,意乱情迷之际

小蝌蚪带她去找了妈妈

深藏功与名

第三关:报复

最后一关

佛曰:“第三关,报仇。报复当初甩掉你的女神和高富帅”

“好的”,蝌蚪微笑,召唤出了夜魔

晚八点,高档餐厅

女神和高富帅在激情派对上亲亲我我

夜魔出现,上台拿起话筒:

“台下的小哥哥,请放下女友的手,大家被我包围了”

现场一片哗然

夜魔:“不是我针对谁,论美色,在座的各位,都是垃圾”

全部人被夜魔的顶配神颜惊呆

夜魔:“我会随机抽一个男人,明天和我一块儿起床”

鲁迅说过:“我想和妳睡觉,是耍流氓。我想和妳起床,是徐志摩”

男人们像疯狗同样欢呼和跪舔

夜魔锁定目标

径直走向高富帅:“小哥哥,你长得好像我下一任男友”

高富帅惶恐不安:“我我我。。。已经。。。”

夜魔强撩:“谈恋爱吗?二缺一”

高富帅捂住心脏:“糟糕,是心动的感受”

一旁的女神暴怒:“我xx妳个xx,勾引我男人”

夜魔一副柔弱装纯的样子:“我只是把他当哥哥~”

女神继续:“我xx妳个xx”

夜魔无辜的看着高富帅:“都怪我,害你女友生气了”

高富帅沦陷:“不要理会那八婆”

女神:“我xx妳个xx”

夜魔:“她好凶,我好怕”

高富帅:“不要怕,个人当心心,紫薯于妳”

鲁迅说过:“渣女装纯,天下无敌”

高富帅沦为了夜魔的裆下亡魂

女神跪下,掩面痛哭

这一切,都是小蝌蚪的精心策划

佛主出现:“恭喜小蝌蚪,你成为了一位顶级渣男”

小蝌蚪:“佛心四大皆空,贫僧尘念已结”

佛曰:“我现赐予你法号——渣佛”

佛曰:“但愿你从此,随老衲去夜店降妖除魔,还人间一片净土”

小蝌蚪:“哦咪陀佛”

小蝌蚪终于成为了江湖第一的渣男

手段虽然残忍

但咱们不要怪渣男渣

由于每一个渣男背后,都有一段刻骨铭心的虐恋

每一位渣男,都曾是折翼的天使

甩掉女神那天晚上

小蝌蚪的肩膀上靠着富婆

车里循环了一首歌:

i lost myself again

我又一次迷失了本身

but i still remember you

脑海中的妳依然那么深入

don't come back

别回头看我,那些伤还未愈合

our love is six feet under

咱们的爱已深埋殆尽

i can't help but wonder

不能本身的我很想知道

if our grave was watered by the rain

滂沱大雨后,埋葬咱们爱的地方

would rose bloom

是否会有玫瑰,悄然绽开

————《six feet under》

做者:第一名的小蝌蚪

微信公众号:前端屌丝

github: github.com/airuikun/bl…

《 蝌蚪传记:200行代码实现前端无痕埋点 》

背景

上次公开演讲结束后,不少小伙伴对无痕埋点很感兴趣

那此次就讲讲前端无痕埋点的原理与实现吧。

鲁迅说过:“一切不放源码的技术文章都是耍流氓”

因此无痕埋点源码:smart-tracker

什么是无痕埋点

简单来讲,就是当引入无痕埋点的库之后

用户在浏览器里全部行为和操做都会被自动记录下来

并将信息发送到后端进行统计和分析

传统的埋点形式,都是手动埋点

在指定的元素上绑定事件

将用户行为信息发送到服务端进行统计

假设若是有一万个点须要前端狗去埋,惊喜不惊喜,意外不意外

咱们为何要作无痕埋点

提升工做效率,解放双手

屌丝的双手获得解放之后

就有更多的时间拿双手来取悦本身

嘻嘻

无痕埋点原理

原理很简单,这里只讲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有个好处就是轻量,而且还支持跨域

打点基本上都用的这个方法进行发送数据

结尾

两个多月没写文章了,由于在忙着晋升

此次晋升最大的感悟就是,若是你只一心专一业务,是很难晋升成功的

须要在平常工做中作一些技术型需求

而无痕埋点,是一个不错的选择

可是这篇文章仅仅只是无痕埋点的一个简单实现

对整个无痕埋点体系来讲,这些只是冰山一角

真正的无痕埋点,还须要作统计、分析、差量预测、标记策略、智能降噪、可视化无痕、无痕分桶、反向推导热力图、大数据中台等等 涉及到前端、后端、运维、DBA和算法

一块儿干下来,那你就是江湖顶级的前端渣男了

以上就是文章的所有了,谢谢你能所有看完

最后,祝你过上幸福快乐的生活

做者:第一名的小蝌蚪

微信公众号:前端屌丝

github: github.com/airuikun/bl…

往期文章

相关文章
相关标签/搜索