微信小程序--模块曝光埋点方法

我们在处理模块曝光埋点时,需要根据页面滚动的位置判断模块是否可见(被曝光)。Web 上传统方法是增加页面 scroll 监听事件,根据滚动位置与模块位置进行对比判断,小程序上也可以使用这种方法,但现在有更便捷优雅的替代方案 —— IntersectionObserver 对象。

IntersectionObserver 对象

IntersectionObserver 对象,用于推断某些节点是否可以被用户看见,下面将介绍相关的 API:

(1) 创建

通过 this.createIntersectionObserver 创建,该方法可传入的参数有三个:

  • <u style="word-wrap: break-word; margin: 0px; padding: 0px; text-decoration: none; font-style: normal;">thresholds</u> :数值数组,代表相交比例的阈值(可有多个,取值范围 [0,1] ),当相交到达该阈值时会触发一次监听回调,在曝光埋点场景下设置为中间位置 [0.5] 即可;
  • <u style="word-wrap: break-word; margin: 0px; padding: 0px; text-decoration: none; font-style: normal;">initialRatio</u> :初始相交比例,如果方法调用时检测到的相交比例与这个值不相等且达到阈值,则会触发一次监听器的回调函数,在曝光埋点的场景下设置为默认值0即可;
  • <u style="word-wrap: break-word; margin: 0px; padding: 0px; text-decoration: none; font-style: normal;">observeAll</u> :是否同时观测多个目标节点;

(2) 设置参考区域

设置参考区域的方法有两个: io.relativeToViewport()io.relativeTo('selector', { ...margins }) ,如果判断相交参考区域是窗口,则使用前者,曝光埋点的场景下就使用这个;后者可用选择器设置其他节点作为相交的参考区域。

(3) 监听

开始监听方法: io.observe(selector, callback) ,selector代表目标模块的选择器,当它和参考区域相交达到阈值比例时,会触发 callback 回调函数,回调函数接受如下几个参数(在该场景中暂时都不会用到):

  • <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> :相交区域的边界;

  • <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> :参照区域的边界;

(4) 取消监听

当页面退出时记得要取消监听:io.disconnect()。

监听相交区域类

我们可以设计一个类,用来处理监听相交区域的逻辑。

构造函数

首先来看构造函数,代码如下:

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
  }
}

显然,构造函数传入了一些重要的参数,包括 createIntersectionObserver 所需要的三个参数:thresholds, initialRatio, observeAll 和上下文 context ;设置参考区域所需的 relativeTo ;监听方法所需的目标模块选择器 selector

最后还有 IntersectionObserver 类监听调用时需要的三个参数:

  • onEach:每一次触发监听调用时,也会调用 onEach 方法;
  • onFinal:在触发监听调用一段时间 delay 后,会调用一次 onFinal 方法。在模块曝光埋点场景下,如果页面在快速滚动时,每次的监听触发都上报埋点,一时间请求会堆积很多,所以需要onFinal 方法,在一段时间后统一上报曝光埋点;
  • delay:调用 onFinal 方法的间隔时间;

监听

要想开始监听相交区域,需要先创建监听器,设置完相交区域后再开始监听,关键代码如下:

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

  // 创建监听器
  const ob = opt.context
    ? opt.context.createIntersectionObserver(observerOptions)
    : wx.createIntersectionObserver(null, observerOptions)

  // 相交区域设置
  if (opt.relativeTo) ob.relativeTo(opt.relativeTo)
  else ob.relativeToViewport()

  // 开始监听
  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    // 正在收集监听结果,不会调用 onFinal
    isCollecting = true    

    // 设置延迟调用 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
}

封装停止监听的方法:

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…

总结

当然,曝光埋点也可以使用传统 Web 的监听 scroll 事件的方式。不过,既然小程序提供了 IntersectionObserver API 并且几乎所有客户端都已支持,那自然就用这种更方便的方式。

另外,在百度小程序和支付宝小程序上也有支持相关的API,跨端开发也不用考虑其他小程序不支持。

关于兼容性

支付包小程序兼容性有待考证,百度可以使用 IntersectionObserver ,不过需要注意this.createIntersectionObserver 非组件是没有的,只能使用swan.createIntersectionObserver(this);第二点, createIntersectionObserver 的参数observeAll 需要改成 selectAll (百度小程序代码片段: swanide://fragment/142c0f60156b1e850dc239553ecffe7b1571810456384 )。

参考文档

  1. 官方文档
  2. 谈谈IntersectionObserver懒加载 (Web API 表现形式详解,和小程序上相同);

作者:w_西城

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,233评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,013评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,030评论 0 241
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,827评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,221评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,542评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,814评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,513评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,225评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,497评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,998评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,342评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,986评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,812评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,560评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,461评论 2 266

推荐阅读更多精彩内容