如何通過Vue自定義指令實現(xiàn)前端埋點詳析
前言
在營銷活動中,通過埋點可以獲取用戶的喜好及交互習慣,從而優(yōu)化流程,進一步提升用戶體驗,提高轉化率。
在之前的埋點方案實現(xiàn)中,都是在具體的按鈕或者圖片被點擊或者被曝光時主動通過事件去上報埋點。這種方法在項目中埋點比較少時還行,一旦項目中需要大量埋點時,不可避免的要添加很多業(yè)務代碼。也很大程度上造成了埋點邏輯與業(yè)務邏輯的高耦合。
為了改造這種情況,我們對于原有的埋點方式做了一些小改進,使得埋點效率得到了極大提升。
在闡述我們的埋點改造之前,有必要對埋點的一些常識做下簡單的了解。
埋點上報方式都有哪些?
要知道埋點的類型有很多,上報的方式也是五花八門。前端常見的埋點方法有三種:
- 手動埋點
- 可視化埋點
- 無痕埋點
手動埋點,顧名思義就是純手動寫代碼,調(diào)用埋點 SDK 提供的函數(shù),在需要埋點的業(yè)務邏輯中添加對應方法,上報埋點數(shù)據(jù)。這種也是之前一直在使用的方法。
可視化埋點是指通過可視化系統(tǒng)配置埋點,這種方式接觸的不是很多,就不展開說了。
無痕埋點,也叫自動埋點、全埋點。即對全局所有事件和頁面加載周期進行攔截埋點。
一般對哪些數(shù)據(jù)做埋點?
為了達到數(shù)據(jù)分析,便于后續(xù)的運營及產(chǎn)品策略調(diào)整的目的,一般需要對以下幾點做埋點統(tǒng)計:
- 頁面埋點:統(tǒng)計用戶進入或者離開頁面的信息,如頁面瀏覽次數(shù)(pv)、瀏覽頁面人數(shù)(uv)、頁面停留時長、設備信息等
- 點擊埋點:統(tǒng)計用戶在頁面瀏覽過程中觸發(fā)的點擊事件,如按鈕、導航或者圖片的點擊次數(shù)
- 曝光埋點:統(tǒng)計具體元素是否得到有效曝光
需求分析
本文是基于最近項目中添加埋點的需求,我們需要的一種理想化方案是:
- 埋點與業(yè)務盡量分離,埋點邏輯更應該是獨立于業(yè)務的
- 盡量不對業(yè)務代碼有侵入
- 約定規(guī)范,通過統(tǒng)一收口來處理埋點邏輯
由于項目是Vue開發(fā)的,所以考慮使用自定義指令的方式來完成埋點上報。選擇自定義指令的原因也是因為他能一定程度上能讓業(yè)務和埋點解耦。
頁面埋點在框架層面已經(jīng)幫我們做掉了,這里主要關心的是點擊埋點和曝光埋點。
實現(xiàn)思路其實也很清晰:在需要埋點的DOM節(jié)點掛載特殊屬性,通過埋點SDK監(jiān)聽掛載了相應屬性對應的事件,在事件觸發(fā)時進行埋點數(shù)據(jù)上報。
那么問題來了,怎么監(jiān)聽呢?
對于點擊事件,我們可以采用addEventListener來監(jiān)聽click事件。這很簡單。
對于元素的曝光就稍微有點麻煩了。
首先我們來看一下為什么需要監(jiān)測曝光:

為了衡量用戶對產(chǎn)品的興趣程度,需要計算區(qū)域的點擊率(點擊次數(shù)/曝光次數(shù))。為了保證點擊率的準確性,我們必須保證用戶真正的瀏覽到了這些產(chǎn)品(就比如上圖中最下方的機酒產(chǎn)品區(qū)域,由于需要滾動頁面,用戶才有可能看到這一區(qū)域)。
那么怎么判斷元素出現(xiàn)在頁面的可視區(qū)域呢?
按照以往的做法:監(jiān)聽滾動事件,通過getBoundingClientRect()方法計算監(jiān)測區(qū)域與視窗的位置,然后判斷元素是否出現(xiàn)在頁面的可視區(qū)域內(nèi)。但是由于scroll事件的頻繁觸發(fā),性能問題很大。
基于此,瀏覽器特意為我們打造了一個Intersection ObserverAPI,把性能相關的細節(jié)都處理掉,讓開發(fā)者只關心業(yè)務邏輯即可:

由于用戶瀏覽頁面的不確定性,還必須要避免重復的曝光行為。這個在曝光之后,移除觀察即可。
代碼實現(xiàn)
上面的需求分析還是比較抽象,下面讓我們結合代碼來看一下最終的實現(xiàn)。
Click 類封裝
點擊事件的處理相對比較簡單,每次點擊觸發(fā)數(shù)據(jù)上報即可:
// src/directives/track/click.js
import { sendUBT } from "../../utils/ctrip"
export default class Click {
add(entry) {
// console.log("entry", entry);
const traceVal = entry.el.attributes["track-params"].value
const traceKey = entry.el.attributes["trace-key"].value
const { clickAction, detail } = JSON.parse(traceVal)
const data = {
action: clickAction,
detail,
}
entry.el.addEventListener("click", function() {
console.log("上報點擊埋點", JSON.parse(traceVal))
console.log("埋點key", traceKey)
sendUBT(traceKey, data)
})
}
}Exposure 類封裝
曝光的相對復雜一些。
首先通過new IntersectionObserver() 實例化一個全局_observer,如果得到有效曝光的(這里當元素出現(xiàn)一半以上則進行曝光),就去獲取 DOM 節(jié)點上的trace-key(埋點 key)和track-params(埋點 value)。
// src/directives/track/exposure.js
import "intersection-observer"
import { sendUBT } from "../../utils/ctrip"
// 節(jié)流時間調(diào)整,默認100ms
IntersectionObserver.prototype["THROTTLE_TIMEOUT"] = 300
export default class Exposure {
constructor() {
this._observer = null
this.init()
}
init() {
const self = this
// 實例化監(jiān)聽
this._observer = new IntersectionObserver(
function(entries, observer) {
entries.forEach((entry) => {
// 出現(xiàn)在視窗內(nèi)
if (entry.isIntersecting) {
// 獲取參數(shù)
// console.log("埋點節(jié)點", entry.target.attributes);
const traceKey = entry.target.attributes["trace-key"].value
const traceVal = entry.target.attributes["track-params"].value
console.log("traceKey", traceKey)
console.log("traceVal", traceVal)
const { exposureAction, detail } = JSON.parse(traceVal)
const data = {
action: exposureAction,
detail,
}
// 曝光之后取消觀察
self._observer.unobserve(entry.target)
self.track(traceKey, data)
}
})
},
{
root: null,
rootMargin: "0px",
threshold: 0.5, // 元素出現(xiàn)面積,0 - 1,這里當元素出現(xiàn)一半以上則進行曝光
}
)
}
/**
* 元素添加監(jiān)聽
*
* @param {*} entry
* @memberof Exposure
*/
add(entry) {
this._observer && this._observer.observe(entry.el)
}
/**
* 埋點上報
*
* @memberof Exposure
*/
track(traceKey, traceVal) {
// console.log("曝光埋點", traceKey, JSON.parse(traceVal));
sendUBT(traceKey, traceVal)
}
}指令封裝
有了點擊和曝光類,下一步就是 Vue 指令的封裝了,也是之所以能實現(xiàn)半自動埋點的核心。
這里存在一個場景就是對于同一個按鈕或者圖片,同時存在既需要點擊埋點又需要曝光埋點的場景。所以在指令的設計時支持了單獨傳入和同時傳入的場景:
v-track:click|exposurev-track:exposure
// src/directives/track/index.js
import Vue from "vue"
import Click from "./click"
import Exposure from "./exposure"
// 實例化曝光和點擊
const exp = new Exposure()
const cli = new Click()
Vue.directive("track", {
bind(el, binding) {
// 獲取指令參數(shù)
const { arg } = binding
arg.split("|").forEach((item) => {
// 點擊
if (item === "click") {
cli.add({ el })
} else if (item === "exposure") {
exp.add({ el })
}
})
},
})同時需要在src/index.js引入即可:
import "./directives/track"
使用
在需要埋點的地方使用也是很簡單的:
<img
ref="imageDom"
trace-key="o_img"
v-track:click|exposure
:track-params="
JSON.stringify({
exposureAction: 's_pictures',
clickAction: 'c_pictures',
detail: {
value: '測試',
},
})
"
/>不足
通過Vue自定義指令的一個簡單封裝,業(yè)務代碼和埋點代碼就達到了一定的解耦,相較之前,無論是埋點的開發(fā)成本還是維護成本都降低了很多。
但是這也只是一個最簡單的實現(xiàn),還有很多情況需要考慮:
- 曝光時頻次很高,是否可以考慮批量上報?
- 用戶訪問一半頁面,突然切出,之后又重新進入,這種情況埋點又該如何上報?
- 用戶設備不支持
Intersection ObserverAPI 情況,是否要考慮向下兼容?
鑒于這套埋點方案還在不斷完善中,等后續(xù)完善并在業(yè)務中落地平穩(wěn)運行后。我再分享其中的細節(jié)給到大家。
總結
到此這篇關于如何通過Vue自定義指令實現(xiàn)前端埋點的文章就介紹到這了,更多相關Vue實現(xiàn)前端埋點內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
html+vue.js 實現(xiàn)漂亮分頁功能可兼容IE
功能比較簡單,在單一html中使用vue.js分頁展示數(shù)據(jù),并未安裝腳手架,或使用相關UI框架,此時需要手寫一個分頁器,不失為最合理最便捷的解決方案,需要的朋友可以參考下2020-11-11
詳解vue-router數(shù)據(jù)加載與緩存使用總結
這篇文章主要介紹了詳解vue-router數(shù)據(jù)加載與緩存使用總結,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-10-10
解決vue組件沒顯示,沒起作用,沒報錯,但該顯示的組件沒顯示問題
這篇文章主要介紹了解決vue組件沒顯示,沒起作用,沒報錯,但該顯示的組件沒顯示問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09
vue.js樣式布局Flutter業(yè)務開發(fā)常用技巧
這篇文章主要為大家介紹了vue.js樣式布局Flutter業(yè)務開發(fā)中的常用技巧,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪2021-11-11

