vue聲明式埋點實踐

本文介紹了針對vue的聲明式埋點,如何作vue的聲明式埋點,使用方便,與腳本邏輯解耦,目前應用在斑馬和捕手等衆多平臺html

埋點方案的嘗試

目前現有的埋點方案有命令式埋點、聲明式埋點、可視化埋點、無痕埋點前端

  • 命令式埋點是用比較常見的方式,在用戶產生行爲的地方使用js方法進行數據上報,優勢是埋點方式比較簡單,缺點是與業務耦合度較高
  • 聲明式埋點是在具體DOM元素上進行數據綁定,只需組件開發人員在sdk上制定埋點方案,業務開發人員設置數據便可,優勢是埋點代碼與具體的交互和業務邏輯解耦
  • 可視化埋點是經過可視化工具配置埋點,須要另外配套一個平臺控制埋點的埋入,優勢是自動生成埋點代碼嵌入到頁面中,減輕業務開發人員的埋點負擔,目前作得好得例如Mixpanel
  • 無埋點是前端自動採集所有事件,上報埋點數據,由後端來過濾和計算出有用的數據,優勢是徹底無需業務參與,徹底與業務解耦,目前比較流行的例如GrowingIO

本埋點應用在電商平臺,要埋的點比較繁多善變,使用聲明式埋點是比較合適的vue

聲明式埋點

vue中提供了自定義指令,在模版元素中插入自定義指令,能夠跟蹤元素的結構變化,跟蹤數據變化,比DOM的data屬性更加方便抓取跟蹤git

按照官方文檔一個指令定義對象提供以下幾個鉤子函數:github

  • bind:只調用一次,指令第一次綁定到元素時調用。在這裏能夠進行一次性的初始化設置。
  • inserted:被綁定元素插入父節點時調用 (僅保證父節點存在,但不必定已被插入文檔中)。
  • update:所在組件的 VNode 更新時調用,可是可能發生在其子 VNode 更新以前。指令的值可能發生了改變,也可能沒有。可是你能夠經過比較更新先後的值來忽略沒必要要的模板更新。
  • componentUpdated:指令所在組件的 VNode 及其子 VNode 所有更新後調用。
  • unbind:只調用一次,指令與元素解綁時調用。

指令鉤子函數會被傳入如下參數:後端

  • el:指令所綁定的元素,能夠用來直接操做DOM。
  • binding:一個對象,包含指令的指令名、綁定值、表達式等。

其中bind和update是比較重要的兩個鉤子函數,它能跟蹤DOM的出現和變化,獲取數據並數據上報埋點,具體的代碼以下:數組

Vue.directive('bury-click', {
  bind(el, binding) {
    _ga.buryClick(el, binding)
  },
  update(el, binding) {
    _ga.buryClickUpdate(el, binding)
  },
  unbind(el) {
    _ga.cancelBuryClick(el)
  }
})
複製代碼

整個指令的生命週期以及埋點的數據收集方式以下圖所示緩存

聲明式埋點

實現方式

根據現有的埋點需求,主要實現了頁面曝光、坑位曝光、坑位點擊三種形式app

  • 頁面曝光:對於vue的單頁應用來講,頁面的切換跟蹤就是路由的變化,可是在統一的路由鉤子放置每一個頁面不一樣的數據不太現實,因而就考慮在每一個view頁面根部埋下頁面曝光數據,只要用戶一訪問該頁面,就觸發頁面曝光
  • 坑位曝光:坑位的曝光實際就是一個DOM出如今用戶視野範圍內進行抓取,須要藉助全局滾動(scroll)事件,使用節流的方式檢測目標坑位是否在可視範圍內,在的話就觸發坑位曝光
  • 坑位點擊:坑位的點擊須要對目標坑位進行點擊事件綁定,在不影響目標坑位原有事件基礎上,綁定點擊的埋點上報,在元素unbind的時候解除對應點擊事件

針對以上三種狀況,不入侵業務的腳本邏輯,制定了三個自定義指令v-page-exposurev-exposurev-bury-click函數

  • v-page-exposure
<div class="root" v-page-exposure="'1.1.0.0'"></div>
複製代碼

如代碼指令所示,a.b.c.d分別爲應用代碼.頁面代碼.模塊代碼.坑位代碼,就是埋點統計須要的代碼信息,把信息收集上報便可。須要注意的是指令信息是一個js表達式,若是不加引號會默認執行js變成一個對象取值報錯。

  • v-exposure
<div v-exposure="{gcms:[{type:1, uri:22},{type:2, uri:41}],seq:[1],spm:'1.0.0.0'}"></div>
複製代碼

坑位曝光收集的是一個js對象,包含一些坑位的代碼信息、位置信息、商品信息、跳轉信息等。坑位曝光采用實時上報,且曝光一次就再也不曝光,因此每次bind的時候把全部曝光坑位收集在一個數組,坑位出如今用戶可視範圍內一次就上報彈出數組,具體的代碼以下:

buryExposure(el, binding) {
  this.exposureList.push({
    el,
    binding: binding.value
  })
}

exposure() {
  if (this.exposureList.length !== 0) {
    for (let i = 0; i < this.exposureList.length; i++) {
      let item = this.exposureList[i]
      const currTop = item.el.getBoundingClientRect().top + window.pageYOffset
      const scrollTop = document.documentElement.scrollTop
      // 修正5像素的誤差
      if (currTop + 5 >= scrollTop && currTop < (scrollTop + window.innerHeight)) {
        // 發送曝光事件
        if (isWebview) {
          this.appAction()
        } else {
          this.action()
        }
        this.exposureList.splice(i, 1)
        i--
      }
    }
  }
}
複製代碼
  • v-bury-click
<div v-bury-click="JSON.stringify({gcms:[{type:1, uri:22},{type:2, uri:41}],spm:'1.0.0.0'})"></div>
複製代碼

坑位點擊也是一個js對象,包含坑位的各類信息,在頁面加載的時候綁定點擊事件,用戶點擊的時候上報埋點。在實際使用過程當中埋點須要跟蹤最新的數據信息,好比在加入購物車的環節中,加入購物車的按鈕是同一個不變,但下一次選擇商品的信息可能發生改變,因此每次點擊按鈕須要傳遞最新的埋點信息。因爲指令信息是一個js表達式,對象是一個引用類型,改變對象的值不會觸發update鉤子函數,因此須要JSON字符串化一下。具體的代碼以下:

buryClick(el, binding) {
  el.addEventListener('click', this.click.bind(this, el))
}

click(el) {
  ...
  this.gaData.ext = encodeURIComponent(JSON.stringify({ eventId: '2', ...value }))
  if (isWebview) {
    this.appAction()
  } else {
    this.action()
  }
}
複製代碼

附加信息

除了埋點點位信息以外,還須要一些經常使用的基礎信息,好比用戶信息、系統信息、會話信息、端信息等等,都是能夠經過頁面初次加載的時候收集。另外還須要驗證埋點請求,要在業務請求頭中埋入埋點的信息,這些信息只存在於埋點的緩存中,因而就重寫XHR和fetch請求,在每次發送請求前加入須要的埋點信息,與業務解耦。

相關文章
相關標籤/搜索