web埋点方案-react项目利用H5自定义属性实现全局监听用户点击事件

  最近项目需要收集用户点击事件并进行操作习惯、模块实用度等分析。在多次调研中发现,网上很多只提供了局部解决思路。后来经过多次尝试、综合了多种方案,最终决定用以下方案实现事件收集并上报存储。(我先一步步利用代码片段带入讲解,全部的代码在最后)

关键词

  • H5自定义属性
  • React
  • 监听
  • 全局
  • 自定义元素
  • 定时上报

开始之前先了解以下两点

  1. 埋点方案大致分为代码埋点、可视化埋点和全埋点,三种方案的区别和具体介绍可以参考这篇文章,我在实验中使用的全埋点方案,就是页面全局自定义元素监控。
  2. 全埋点的关键在于H5的自定义属性,关于该属性的介绍可以参考这篇文章

开始收集

  先制造一下业务场景,以下方我的react demo为例,如图,例如我现在在开发网上商城、我要监听用户点击下方商品种类的次数。在这里插入图片描述

步骤1:在要监听的组件中埋入自定义属性

  在要监听的组件中埋入自定义属性,先约定自定义属性为data-listened,属性的值即为所要区分的业务类型,例如手机类的业务类型就是moudule-entry-telephone,在项目中,最好把属性名放在全局配置中,各个组件统一引用。示例代码:

<div href="#" data-listened="moudule-entry-telephone">手机类</div>
<div href="#" data-listened="moudule-entry-office">办公类</div>
<div href="#" data-listened="moudule-entry-sport">运动类</div> 
<div href="#" data-listened="moudule-entry-book">图书类</div>
<div href="#" data-listened="moudule-entry-fashion">时尚类</div>
<div href="#" data-listened="moudule-entry-clothes">穿搭类</div>       
步骤2:添加全局监控

  在react最高层组建中添加全局监控,一般是在app.js,添加全局监控一定要在组件加载完成之后监控,即在componentDidMount生命函数中引用。关键代码:

 // 获取到页面所有的被监听的元素,即具有自定义属性“data-listened”的元素
 const listenedEles = document.querySelectorAll("[data-listened]") || [];

 // 遍历所有被监听的元素,并添加监听事件
 listenedEles.forEach(ele => {
   // 当被点击后,获取到被点击元素的业务类型,即自定义属性“data-listened”的属性值
   ele.onclick
     = function () {
       // 暂时收集起来,设置定时任务进行上报(提交给服务端)并清空
       recordCollecter(ele.getAttribute("data-listened"))
     }
 })

上报数据

  上报方案我采用了先暂存再批量上传的方式,需要处理好暂存变量和上传的先后逻辑。

// 点击事件将会记录在这里
let records = [];

// 点击事件收集器
function recordCollecter(type) {
  // 这里上传的列表属性就要根据自己情况定了,暂定一个type和时间戳作为演示
  records.push({ type, time: new Date() })
}

// 1、定时上报(5s)
// 2、上报后重新收集
setInterval(() => {
  if (records.length > 0) {
    setTimeout(() => {
      console.log(records);// 1、定时上报,这里要换成上报接口但是我没有开发,暂时打印出来作为演示
      records = [];// 2、上报后重新收集,这里在清空的时候不会漏记
    }, 0);
  }
}, 5000)

基本功能测试

  为了验证收集的正确性,我将以每5秒从控制台输出一次暂存的收集数据,并将收集的条数和自己写的全局鼠标监控次数进行对比。(监控鼠标点击次数代码就省略了,react基本技能)
  如下图所示,我依次点击了时尚类、图书类和运动类,我的三次点击已经成功收集并从控制台打印出来。在这里插入图片描述

进一步测试

  为了验证收集的完整性,我将进行很多次点击,并将打印的数据条数累加起来和鼠标点击的次数进行对比。
  如下图所示,我在20秒内点击了66次,控制台分四次打印出来(每5秒打印依次),所得结果13+22+19+22=66,所以完整性是没问题的。在这里插入图片描述

脱离html文档流的监控问题

  我的监控是在html中监控的,那么脱离文档流还可以监控到吗?答案是肯定的,我在另一台电脑上亲测有效,具体就不演示了。
(什么是脱离文档流?参考这里

代码白给环节

全局组件app.js
import React from 'react';
import logo from './logo.svg';
import './App.css';
import userOperateRecorder from "./userClickListener/recorder.js"

class App extends React.Component {

  constructor(props) {
    super(props);
    // 初始化鼠标点击次数
    this.state = { count: 0 };
  }

  componentDidMount() {
    // 调用用户操作监控组件
    userOperateRecorder()
  };

  // 鼠标点击计数
  mouseCount() {
    this.setState({
      count: this.state.count + 1
    })
  }
  render() {
    return (
      <div className="App" onMouseDown={() => this.mouseCount()} >
        <header className="App-header">
          {/* 为了验证事件有没有漏记,同时全局监听了鼠标点击事件 */}
          <div className="mouse-count">鼠标点击了{this.state.count}</div>
          <div >例如我现在在开发网上商城、我要监听用户点击下方商品种类的次数:</div>
          {/* 被监听事件只用定义"data-listened"属性,并指定业务类型,即"data-listened"的值 */}
          {/* "data-listened"属性说明:H5支持自定义属性标签,规范都是"data-"作为前缀 */}
          <div href="#" data-listened="moudule-entry-telephone">手机类</div>
          <div href="#" data-listened="moudule-entry-office">办公类</div>
          <div href="#" data-listened="moudule-entry-sport">运动类</div>
          <div href="#" data-listened="moudule-entry-book">图书类</div>
          <div href="#" data-listened="moudule-entry-fashion">时尚类</div>
          <div href="#" data-listened="moudule-entry-clothes">穿搭类</div>

        </header>
      </div >
    );
  }
}

export default App;

监控和上报方法recorder.js
/*
 * @Author: zhaoheng
 * @Date: 2020-01-12 17:21:15
 * @LastEditTime : 2020-01-12 20:44:06
 * @LastEditors  : Please set LastEditors
 * @Description: 埋点监控用户点击事件
 * @FilePath: \react-demo\src\userClickListener\recorder.js
 */
function userOperateRecorder() {


  // 获取到页面所有的被监听的元素,即具有自定义属性“data-listened”的元素
  const listenedEles = document.querySelectorAll("[data-listened]") || [];

  // 遍历所有被监听的元素,并添加监听事件
  listenedEles.forEach(ele => {
    // 当被点击后,获取到被点击元素的业务类型,即自定义属性“data-listened”的属性值
    ele.onclick
      = function () {
        // 暂时收集起来,设置定时任务进行上报(提交给服务端)并清空
        recordCollecter(ele.getAttribute("data-listened"))
      }
  })

  // 点击事件将会记录在这里
  let records = [];
  
  // 点击事件收集器
  function recordCollecter(type) {
    // 这里上传的列表属性就要根据自己情况定了,暂定一个type和时间戳作为演示
    records.push({ type, time: new Date() })
  }

  // 1、定时上报(5s)
  // 2、上报后重新收集
  setInterval(() => {
    if (records.length > 0) {
      setTimeout(() => {
        console.log(records);// 1、定时上报,这里要换成上报接口但是我没有开发,暂时打印出来作为演示
        records = [];// 2、上报后重新收集,这里在清空的时候不会漏记
      }, 0);
    }
  }, 5000)
}
export default userOperateRecorder;
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值