前端埋點之曝光實現


最近有一個工作需求是曝光埋點,讓我得以有機會接觸相關的東西。之前實習時沒有做過這方面的需求,個人項目更是和埋點扯不上關系。以至於上周開會討論時聽到“埋點”這個詞就慫了。

不過后面聽大佬分析了下后才意識到,原來“埋點”是這個意思。曝光埋點的思路也是很簡單:無非是判斷某個DOM是否出現在視窗中,出現了就收集數據上報給服務端。

所謂“埋點”,是數據采集領域(尤其是用戶行為數據采集領域)的術語,指的是針對特定用戶行為或事件進行捕獲、處理和發送的相關技術及其實施過程。比如用戶某個文章點擊次數、觀看某個視頻的時長等等。

再說「曝光埋點」,它與「圖片懶加載」「計算廣告瀏覽量」這些需求一樣,本質就是讓你計算某一元素和另一元素(視窗)的相對可視狀態/相對位置,然后進行一些操作(一般是上報給服務端)。

 

思考如何實現

最先出現在腦海里的方法是利用getBoundingClientRect / offset類 + onscroll。即:注冊滾動事件,然后在滾動的回調函數中利用getBoundingClientRect / offset類拿到每個元素的位置信息,然后經過判斷確定是否元素處於曝光狀態/視窗中。

但這種方式有很大的缺陷。如果你熟悉瀏覽器的渲染過程的話,就會知道調用getBoundingClientRect / offset類會引起瀏覽器的回流重繪,影響網頁表現/性能。頻繁、大量調用更不是一個妥當的選擇。

我開始嘗試在社區找找看有沒有其他更妥當的方法,還真被我找到了:Intersection Observer

 

Intersection Observer

它提供了一種異步觀察目標元素與祖先元素或頂級文檔Viewport的交集變化的方法。也就是說,不僅可以用來獲得相對於視窗的曝光,可以做得更多,這取決於“另一個元素”是什么。

Intersection Observer將本來是開發者做的:監聽滾動、遍歷獲取元素與另一個元素(或視窗)相對位置的工作給做了。這兩塊工作是頁面性能損耗大戶,現在交給瀏覽器來實現,會比我們開發者來做要妥當的多。開發者現在只需要關心其他業務邏輯即可 

那這么好用的API,它的兼容性狀況如何呢?

還不錯,但兼容性方面要求高的話還是不能讓人放心使用。

 

Polyfill

但不用擔心,我們有polyfill。W3C提供了一個polyfill,當瀏覽器不支持時使用常規解決方案替代。它的思路就是在檢測到當前瀏覽器不支持Intersection Observer API時,使用getBoundingClientRect去重新實現一遍Intersection Observer API。

那么使用了該Polyfill后,瀏覽器兼容性狀況如何呢?

非常棒! (IE7都支持了,還想啥呢,大兄弟。)

 

曝光實現步驟

思路就像上面一再提到的,很簡單:

  1. new IntersectionObserver() 實例化一個全局observer,(結合vue指令)讓每個DOM自行把自己加入到observer的觀察列表。
  2. 當某個DOM進入視窗,收集對應的信息,上報。
  3. 取消對該DOM的觀察。

豌豆資源搜索網站https://55wd.com 廣州vi設計公司http://www.maiqicn.com

代碼實現

Exposure.ts 封裝成類

import 'intersection-observer'; export default class Exposure { private observer: IntersectionObserver | undefined; constructor() { this.init(); } private init() { const self = this; this.observer = new IntersectionObserver( (entries, observer) => { entries.forEach(item => { if (item.isIntersecting) { const data = item.target.getAttribute('data-article'); self.upload(data); observer!.unobserve(item.target); } }); }, { root: null, rootMargin: '0', threshold: 0.1, } ); } public add(el: Element) { this.observer && this.observer.observe(el); } private upload(data: string | null) { if (data) { // ajax上報數據 } } }

directive/exposure.ts 封裝vue指令

import Exposure from '@/lib/Exposure'; import Vue from 'vue'; const exposure = new Exposure(); Vue.directive('exposure', { bind(el) { exposure.add(el); }, });

*.vue 使用指令

<div v-exposure :data-article='article'> ... </div>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM