小蝌蚪傳記: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…

往期文章

相關文章
相關標籤/搜索