微信小程序--模塊曝光埋點方法

我們在處理模塊曝光埋點時,需要根據(jù)頁面滾動的位置判斷模塊是否可見(被曝光)。Web 上傳統(tǒng)方法是增加頁面 scroll 監(jiān)聽事件,根據(jù)滾動位置與模塊位置進行對比判斷,小程序上也可以使用這種方法,但現(xiàn)在有更便捷優(yōu)雅的替代方案 —— IntersectionObserver 對象。

IntersectionObserver 對象

IntersectionObserver 對象,用于推斷某些節(jié)點是否可以被用戶看見,下面將介紹相關(guān)的 API:

(1) 創(chuàng)建

通過 this.createIntersectionObserver 創(chuàng)建,該方法可傳入的參數(shù)有三個:

  • <u style="word-wrap: break-word; margin: 0px; padding: 0px; text-decoration: none; font-style: normal;">thresholds</u> :數(shù)值數(shù)組,代表相交比例的閾值(可有多個,取值范圍 [0,1] ),當相交到達該閾值時會觸發(fā)一次監(jiān)聽回調(diào),在曝光埋點場景下設(shè)置為中間位置 [0.5] 即可;
  • <u style="word-wrap: break-word; margin: 0px; padding: 0px; text-decoration: none; font-style: normal;">initialRatio</u> :初始相交比例,如果方法調(diào)用時檢測到的相交比例與這個值不相等且達到閾值,則會觸發(fā)一次監(jiān)聽器的回調(diào)函數(shù),在曝光埋點的場景下設(shè)置為默認值0即可;
  • <u style="word-wrap: break-word; margin: 0px; padding: 0px; text-decoration: none; font-style: normal;">observeAll</u> :是否同時觀測多個目標節(jié)點;

(2) 設(shè)置參考區(qū)域

設(shè)置參考區(qū)域的方法有兩個: io.relativeToViewport()io.relativeTo('selector', { ...margins }) ,如果判斷相交參考區(qū)域是窗口,則使用前者,曝光埋點的場景下就使用這個;后者可用選擇器設(shè)置其他節(jié)點作為相交的參考區(qū)域。

(3) 監(jiān)聽

開始監(jiān)聽方法: io.observe(selector, callback) ,selector代表目標模塊的選擇器,當它和參考區(qū)域相交達到閾值比例時,會觸發(fā) callback 回調(diào)函數(shù),回調(diào)函數(shù)接受如下幾個參數(shù)(在該場景中暫時都不會用到):

  • <u style="word-wrap: break-word; margin: 0px; padding: 0px; text-decoration: none; font-style: normal;">intersectionRatio</u> : 兩者相交比例;

  • <u style="word-wrap: break-word; margin: 0px; padding: 0px; text-decoration: none; font-style: normal;">time</u> :相交檢測時的時間戳;

  • 各種邊界:

  • <u style="word-wrap: break-word; margin: 0px; padding: 0px; text-decoration: none; font-style: normal;">intersectionRect</u> :相交區(qū)域的邊界;

  • <u style="word-wrap: break-word; margin: 0px; padding: 0px; text-decoration: none; font-style: normal;">boundingClientRect</u> :目標邊界;

  • <u style="word-wrap: break-word; margin: 0px; padding: 0px; text-decoration: none; font-style: normal;">relativeRect</u> :參照區(qū)域的邊界;

(4) 取消監(jiān)聽

當頁面退出時記得要取消監(jiān)聽:io.disconnect()。

監(jiān)聽相交區(qū)域類

我們可以設(shè)計一個類,用來處理監(jiān)聽相交區(qū)域的邏輯。

構(gòu)造函數(shù)

首先來看構(gòu)造函數(shù),代碼如下:

class IntersectionObserver {
  constructor(options) {
    this.$options = {
      context: null,
      threshold: 0.5,
      initialRatio: 0,
      observeAll: false,
      selector: null,
      relativeTo: null,
      onEach: res => res.dataset,
      onFinal: () => null,
      delay: 200,    
      ...options,
    }
    this.$observer = null
  }
}

顯然,構(gòu)造函數(shù)傳入了一些重要的參數(shù),包括 createIntersectionObserver 所需要的三個參數(shù):thresholds, initialRatio, observeAll 和上下文 context ;設(shè)置參考區(qū)域所需的 relativeTo ;監(jiān)聽方法所需的目標模塊選擇器 selector

最后還有 IntersectionObserver 類監(jiān)聽調(diào)用時需要的三個參數(shù):

  • onEach:每一次觸發(fā)監(jiān)聽調(diào)用時,也會調(diào)用 onEach 方法;
  • onFinal:在觸發(fā)監(jiān)聽調(diào)用一段時間 delay 后,會調(diào)用一次 onFinal 方法。在模塊曝光埋點場景下,如果頁面在快速滾動時,每次的監(jiān)聽觸發(fā)都上報埋點,一時間請求會堆積很多,所以需要onFinal 方法,在一段時間后統(tǒng)一上報曝光埋點;
  • delay:調(diào)用 onFinal 方法的間隔時間;

監(jiān)聽

要想開始監(jiān)聽相交區(qū)域,需要先創(chuàng)建監(jiān)聽器,設(shè)置完相交區(qū)域后再開始監(jiān)聽,關(guān)鍵代碼如下:

_createObserver() {
  const opt = this.$options
  const observerOptions = {
    thresholds: [opt.threshold],
    observeAll: opt.observeAll,
    initialRatio: opt.initialRatio,
  }

  // 創(chuàng)建監(jiān)聽器
  const ob = opt.context
    ? opt.context.createIntersectionObserver(observerOptions)
    : wx.createIntersectionObserver(null, observerOptions)

  // 相交區(qū)域設(shè)置
  if (opt.relativeTo) ob.relativeTo(opt.relativeTo)
  else ob.relativeToViewport()

  // 開始監(jiān)聽
  let finalData = []
  let isCollecting = false   
  ob.observe(opt.selector, res => {
    const { intersectionRatio } = res
    const visible = intersectionRatio >= opt.threshold
    if (!visible) return

    const data = opt.onEach(res)
    finalData.push(data)

    if (isCollecting) return    // 正在收集監(jiān)聽結(jié)果,不會調(diào)用 onFinal
    isCollecting = true    

    // 設(shè)置延遲調(diào)用 onFinal
    setTimeout(() => {
      opt.onFinal.call(null, finalData)
      finalData = []
      isCollecting = false
    }, opt.delay)
  })
  return ob
}

對外暴露的公用方法

封裝對外的 _createObserver 方法:

connect() {
  if (this.$observer) return this
  this.$observer = this._createObserver()
  return this
}

封裝停止監(jiān)聽的方法:

disconnect() {
  if (!this.$observer) return
  const ob = this.$observer
  if (ob.$timer) clearTimeout(ob.$timer)
  ob.disconnect()
  this.$observer = null
}

使用方法

import IntersectionObserver from './intersection-observer.js';

const ob = new IntersectionObserver({...})
ob.connect()

詳見代碼片段: developers.weixin.qq.com/s/lqUakfmM7…

總結(jié)

當然,曝光埋點也可以使用傳統(tǒng) Web 的監(jiān)聽 scroll 事件的方式。不過,既然小程序提供了 IntersectionObserver API 并且?guī)缀跛锌蛻舳硕家阎С?,那自然就用這種更方便的方式。

另外,在百度小程序和支付寶小程序上也有支持相關(guān)的API,跨端開發(fā)也不用考慮其他小程序不支持。

關(guān)于兼容性

支付包小程序兼容性有待考證,百度可以使用 IntersectionObserver ,不過需要注意this.createIntersectionObserver 非組件是沒有的,只能使用swan.createIntersectionObserver(this);第二點, createIntersectionObserver 的參數(shù)observeAll 需要改成 selectAll (百度小程序代碼片段: swanide://fragment/142c0f60156b1e850dc239553ecffe7b1571810456384 )。

參考文檔

  1. 官方文檔 ;
  2. 談談IntersectionObserver懶加載 (Web API 表現(xiàn)形式詳解,和小程序上相同);

作者:w_西城

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容