数据采集优雅封装

概述

通常一个全新功能上线都会采集用户行为数据,以便数据分析,后续完善优化。而采集数据的行为一般有三个维度:元素点击、元素悬停、元素曝光,下文将研讨如何优雅地采集这三个维度的数据。

方案

原生采集

原生采集顾名思义就是不做任何封装,直接调用第三方数据采集平台提供的SDK(比如,神策提供的Web JS SDK)。

const memoRef = useRef({});
const wait = 2000;

const handleClickTrack = () => {
    if (memoRef.current.prevClickTime) {
        // 已经采集过,无需再次采集
        return;
    }
    if (wait) {
        // 频繁点击设置采集时间间隔
        if (Date.now() - memoRef.current.prevClickTime >= wait) {
            cassSensors.track(eventName, eventData);
            memoRef.current.prevClickTime = Date.now();
        }
    } else {
        // 每次都触发采集
        cassSensors.track(eventName, eventData);
        memoRef.current.prevClickTime = Date.now();
    }
}

这种采集方式简单粗暴可靠,理解比较简单,但缺点也比较突出,含目标元素的组件内部都需要实现采集逻辑,对业务代码的侵入性较强,不便于长期迭代维护(比如GrowingIO替换成神策Web JS SDK)。

Hooks

Hooks利用事件冒泡机制精准拦截目标元素采集行为,属于一种切面思想,抽离采集逻辑,降低对业务组件的侵入性。



  
    
    
    
    Document
    
    
    
  

  
    

上述代码中有以下几处需要注意:

  • 悬停采集,鼠标从包裹元素移动到子元素时会触发mouseout事件,导致采集行为不准确,改用监听mouseleave事件,只有在鼠标移出包裹元素范围才会触发;
  • 曝光采集,初始进入页面,此时用户并没有触发滚动事件,当目标元素在可视区域内,或者用户交互过程使得目标元素呈现在可视区域内,该过程也需要采集曝光。


    这两种场景的关键在于知道目标元素何时呈现,然后再去判断是否在可视区域。当初次渲染或者更新,React生命周期precommit阶段会重新计算绑定在元素上的ref,当ref.current有值,就代表元素已经挂载,可采集曝光。
  • 如果目标元素既要采集点击、悬停,又要采集曝光,可使用封装好的钩子函数useTrackable嵌套包裹

HOC

高阶组件与Hooks实现思想类似,但是高阶组件需要将目标元素单独抽离成组件包装,相对而言,没有Hooks简便



  
    
    
    
    Document
    
    
    
  

  
    

插拔式

前端工程的技术栈有很多,Spring MVC、Vue、React等,如果每种技术栈都去实现一遍,同步维护,成本就比较高了。数据采集都是通过事件机制触发,调用第三方SDK上报,因此可以简单配置目标元素属性,统一拦截采集事件,封装采集逻辑。



  
    
    
    
    
    
    Document
    
  

  
    
目标元素

有几个特殊场景需要注意:

  • 曝光采集,初始页面可视区域的目标元素,和用户交互后呈现出的目标元素应当如何采集?由于此时没有触发滚动事件,scroll事件回调捕获不到,可以利用MutationObserver API监听页面是否有新增DOM,如果有则执行曝光采集逻辑。IE 11以下不支持MutationObserver APIcore-js3并没有实现,可单独引入polyfill来实现;
  • 悬停采集方案,一种是使用mouseentermouseout、mouseleave组合事件监听悬停;另一种是使用mouseover监听悬浮,如果悬浮的是目标元素则执行采集逻辑。如果悬浮的不是目标元素则清除所有悬停定时器;
  • 如果一个元素既要点击采集又要悬停采集,嵌套属性配置会导致其中一个事件采集不到,因为event.target对应层级高的元素,只拿得到一个属性配置项。解决方法一是改造上述配置规则,可配置多事件属性;二是其中一种事件改成手动采集;

    
    
    目标元素
    目标元素
  • 如果目标元素封装在组件内,属性配置项无法穿透组件直接设置到目标元素上,上报不会触发。解决方法一是使用window.cassSensorsTrack手动上报;二是在外层元素添加onMousedownCapture事件捕获拦截,给组件内目标元素添加属性配置;

    const Button = () => 
    // 手动采集
    const handleClickTrack = () => {
      cassSensors.track(eventName, eventData);
    }
    
    // onMousedownCapture比onClickCapture优先级高,利用该事件给目标元素配置属性 const handleMousedownIntercept = () => { const $target = document.getElementById('target'); if ($target) { $target.setAttribute('data-eventname', 'CLICK_EVENT'); $target.setAttribute('data-eventtype', 'click'); $target.setAttribute('data-eventdata', '{ id: "click" }'); $target.setAttribute('data-once', 'false'); $target.setAttribute('data-wait', '1000'); } }
    注:封装埋点插件不采用冒泡机制,而采用捕获机制的原因是有些业务场景下,事情需要阻止冒泡,可能影响到数据采集

    总结

    以上三种方案均能抽离封装采集逻辑,优雅实现数据上报,相对而言,第一种Hooks实现更为简单,便于理解和维护。第三种插拔式插件封装好处在于可在不同技术栈中使用,但配置项较为复杂。

你可能感兴趣的:(采集埋点封装事件流)