React版实现一个简单易用的元素曝光埋点

2,536 阅读4分钟

故事背景

故事要从去年讲起,当时在做一个埋点需求,交互是在一个弹窗(有确认/取消两个按钮),点确认后会弹窗不关闭,展示其他内容。需求是期望对弹窗的内容进行曝光,如图:

当时由于时间问题,采取的方案是硬编码,后期觉得写法太low,就在年底述职的时候立了个Flag,想要改进元素埋点相关方案。改着改着突然发现,其他项目也会偶尔有相关的需求,干脆就抽象封装为一套组件了。

思路

设计这玩意主要是奔着易扩展方向去设计的,因为不知道什么时候就会有新的需求功能。其次是易用、通用,只有易用且兼容大部分系统,其他项目才会去使用你的方案。

之前的想法是从整个项目角度出发,想通过在整个项目的入口(单页应用),监听全局事件去进行。后面发现不可行,难推进、难用、难维护。

因此,换个角度去思考,把角度放在 React.Element 上去看问题。因为在 React 中渲染的内容都可以认为是 React.Element,小到 span 元素,上至整个页面的 Class。从这个方向去设计,可以使得我们的元素曝光埋点更通用。

至于扩展性,在确定实现方案是从元素角度去实现后,那么这边就可以轻松想到使用 HOC 去实现,如图:

在 HOC 中,封装各个方案的逻辑,以后要扩展,直接新增逻辑即可,如下:

效果演示

本组件目前实现了5种效果,分别是:

  1. 元素渲染即曝光
  2. 元素进入到可视区进行曝光
  3. 元素进入到可视区的次数
  4. 元素渲染到销毁的时长,可以大略认为是该元素的停留时长
  5. 元素进入到可视区域到销毁的时长

支持部分的混合使用,比如同时处理统计时长+曝光,更多可以参考文档。

初始化

因为是贴合业务使用的,这边设计的自动发送埋点函数逻辑是贴合我们公司的规范设计的,大家使用的时候可以自行调整,源码会在最后放出。

import { initDig } from ‘element-dig’;

const getAllParams = (evtParams = {}, sourceParams = {}) => {
    return {
        event: evtParams.event,
        uicode: evtParams.uicode, 
        action: {
            user_id: xxxx,
            user_name: xxxx,
            ……
        },
    };
}

// 作者公司业务规范 每个埋点有三种参数,分别是 埋点ID,埋点参数A,埋点参数B
const send = (evtId, evtParams = {}, sourceParams = {}) => { // 通用发送埋点请求
    // evt:事件ID(evt_ID),evtParams 埋点中除了pid、action的字段,sourceParams  埋点参数中的action字段
    window.send(evtId, getAllParams(evtParams, sourceParams)); // 调用真正的埋点发送,这边基于大家自身的业务去改造
}

initDig(send);

该HOC在组件初始化的时候会校验 send 函数的参数个数,如果非0,才认为是正常的函数,使用的时候可以自行改造,我的实现代码如下:

 componentDidMount() {
        if (this.getFuncParameters() === 0) {
            console.warn('请注意,您未传入埋点发送函数,函数发送功能将不可用');
            return;
        }
 		....       
}
 const getFuncParameters = () => {
 	if (typeof window !== 'object') {
    	// 兼容 SSR 渲染模式报错问题
    	return 0;
	}
    const mathes = /[^(]+\(([^)]*)?\)/gm.exec(Function.prototype.toString.call(window[symbol]));
    if (mathes[1]) {
    	const args = mathes[1].replace(/[^,\w]*/g, '').split(',');
    	return args.length;
	}
	return 0; // 返回 0 默认不执行
},

** 注意: **

初始化函数,只需使用一次即可,会自动将函数挂载到 window 上,组件后期会自动调用。推荐单页应用挂载到入口页,多页的话放在本页面的 didmount 生命周期。

元素渲染即曝光

<Exposure
  digData={{
// 默认的模式就是加载即曝光
    evt: 200000,
    evtParams: {
      event: 'ItemExpo',
      uicode: '元素UIcode',
    },
    actionParams: {
      special: '元素简单曝光',
    },
  }}
>
  此处放入将被曝光的元素
</Exposure>

如图,刷新页面,关注第一个 console.log

元素进入到可视区进行曝光

<Exposure
      mode={[‘viewonce‘]}
      digData={{
        evt: 200000,
        evtParams: {
          event: 'ItemExpo',
          uicode: '元素UIcode',
        },
        actionParams: {
          special: '元素可视区域内曝光',
        },
      }}
    >
      此处放入将被曝光的元素
</Exposure>

注意观察滚动后,新增的 console

元素进入到可视区的次数

<Exposure
  mode={[‘view‘]}
  digData={{
    evt: 200000,
    evtParams: {
      event: 'ItemExpo',
      uicode: '元素UIcode',
    },
    actionParams: {
      special: '元素出现在可视区曝光',
    },
  }}
>
  '注意观察控制台的action参数'
</Exposure>

可以看到通过上下滚动,使得该元素出现在屏幕中 3 次,因此返回的结果也是 3 。

元素渲染时长

<Exposure
 mode={[‘ time‘]}
 digData={{
    evt: 200000,
    evtParams: {
      event: 'ItemExpo’,
      uicode: '元素UIcode‘,
    },
    actionParams: {
      special: '时长埋点,注意观察在action参数中的stt,单位是秒‘,
    },
}} 
>
  '注意观察控制台的action参数'
</Exposure>

这里使用按钮触发元素销毁,手动触发统计时间。

元素进入到可视区域到销毁的时长

<Exposure
 mode={[‘timeSinceView‘]}
 digData={{
    evt: 200000,
    evtParams: {
      event: 'ItemExpo’,
      uicode: '元素UIcode‘,
    },
    actionParams: {
      special: '时长埋点,注意观察在action参数中的stt,单位是秒‘,
    },
}} 
>
  '注意观察控制台的action参数'
</Exposure>

该示例,是曝光元素进入到可视区后,才进行统计时间。

以上即是最基础的5种模式的演示,支持部分功能的组合使用~

文档&源码

github地址:github.com/dcison/elem…

** 注意 ** 必然是不能直接 down 了就使用的,除非你们业务埋点的发送函数与我司一样,哈哈哈哈哈~