IntersectionObserver实现曝光埋点

4,476 阅读2分钟

背景

页面中会有一些商品模块,数据组提出了一个需求就是统计当前商品曝光的次数,点击购买的次数,最终下单的次数。获取一个下单转化率

分析

1、点击购买次数可以通过点击购买按钮做买单,下单可以通过点击checkout或者是下单成功之后做埋点。

2、曝光埋点就是,当某一个商品模块展示到可视区域之后做一次埋点,当该商品块滑出去之后,用户再次滑到这个模块的时候在做一次统计。

3、如果通过监听页面滚动查看商品模块展示与否的话性能太差,会不停的触发页面的重绘,性能极差。又没有像android那种可以监听某个view出现在可是去的api。经过一通百度发现浏览器有一个api是IntersectionObserver,可以监听元素的曝光,但是整体的兼容性没有那么好,兼容性情况

4、经过考虑我们主要做的是海外市场,chrome的使用率还是很高,先暂时使用这个api

IntersectionObserver介绍

const io = new IntersectionObserver(callback, option)

io.observe(v) // 开始观察

io.unobserve(el) // 停止观察

io.disconnect() // 关闭观察器


IntersectionObserver是浏览器原生提供的构造函数,接受两个参数,callback是可见性变化时的回调函数,option是配置对象可选参数

callback一般会触发两次,一次是目标进入视口,另一次是完全离开视口

var io = new IntersectionObserver(
  entries => {
    console.log(entries);
  }
);

entries 是一个数组,每一个成员都是一个IntersectionObserverEntry对象

IntersectionObserverEntry对象一共有留个属性

{
  time: 3893.92,
  rootBounds: ClientRect {
    bottom: 920,
    height: 1024,
    left: 0,
    right: 1024,
    top: 0,
    width: 920
  },
  boundingClientRect: ClientRect {
     // ...
  },
  intersectionRect: ClientRect {
    // ...
  },
  intersectionRatio: 0.54,
  target: element
}
  • time: 课件性发生变化的时间,一个高精度时间戳,单位为毫秒
  • target: 被观察的元素,是一个DOM节点对象
  • rootBounds: 根元素的矩形区域的信息,getBoundingClientReact()方法的返回值,如果没有根元素(即直接相对于视口滚动),则返回null
  • boundingClientReact: 目标元素的矩形区域信息
  • intersectionReact: 目标元素与视口(或者根元素)的交叉区域的信息
  • intersectionRatio: 目标元素的可见比例,即intersectionReact占boundingClientReact的比例,完全可见时为1,完全不可见时小于等于0

实现

代码如下

function exposeFn(params) {
  let {
    nodes,
    report,
    disReport
  } = params

  if(!nodes){
    console.warn('没有添加要曝光的node节点')
    return
  }
  const intersectionObserver = new IntersectionObserver(entries => {
    // console.log(entries);
    entries.forEach(entry => {
      // console.log('entry.intersectionRatio', entry.intersectionRatio);
      if (entry.intersectionRatio > 0) {
        // 上报曝光方法
        report && report(entry)
      } else {
        // 将消失在屏幕的元素下掉
        disReport && disReport(entry)
      }
    })
  })

  nodes.forEach(node => {
    intersectionObserver.observe(node)
  })
}

export default class Expose {
  constructor(props) {
    this.from = props.from
    this.sections = []
    this.intersectionObserver = null
    this.init()
  }
  init() {
    let nodes = document.querySelectorAll(".section")
    exposeFn({
      nodes,
      report: this.report,
      disReport: this.disReport
    })
  }

  report(entry) {
    console.log('report ---->', entry.target.getAttribute('data-section'), entry.intersectionRatio, entry)
  }

  disReport(entry) {
    console.log('disreport ---->', entry.target.getAttribute('data-section'), entry.intersectionRatio)
  }
}