小程序从手动埋点到自动埋点

前言

小程序因为封闭性较强,要像web应用同样实现灵活的数据收集,会有必定难度。目前开源的埋点SDK,通常采用手动埋点的方式,这种方式有较强的侵入型,同时开发成本较高,为了解决这个问题就有了该文章。git

手动埋点

以腾讯移动分析的SDK为例,若是要记录埋点信息,只要插入一句代码便可github

// 例如,记录搜索行为
search(keyword) {
   if (keyword) {
       ...业务代码
   }
   // 埋点代码
   mta.Event.stat("ico_search", {"query":keyword});
}
复制代码

示例代码看起来是比较简洁的,可是埋点须要收集的数据每每不是单一的,复杂的埋点代码插入业务代码,会影响代码的阅读体验,并且埋点代码散落在各个地方,不方便管理web

因为手动埋点必须插入到函数中,有时候咱们为了获取页面某一元素点击信息,产生了一种叫无业务相关埋点,简单来讲就是你的函数定义,就只有埋点代码,当这种埋点频繁出现,代码会被严重污染小程序

// wxml
<view bindtap="track">这只是一个展现view</view>

//js 
track() {
  mta.Event.stat("eleClick", {"name":xxxxx});
}
复制代码

另外,因为PM会频繁调整埋点信息,而埋点是一个繁琐又无聊的工做,基于Don't Repeat Yourself 原则,手动埋带要不得。bash

总结以上,手动埋点有下列问题函数

  1. 影响代码的阅读体验
  2. 埋点代码散落在各个地方,不方便管理
  3. 代码会被污染
  4. 埋点是一个繁琐又无聊的工做

自动埋点

一、经过事件冒泡监听元素是否被点击

小程序没有提供Dom的事件监听方法,不过咱们能够经过事件冒泡的方式监听,在wxml最外层绑定catchtap事件获取点击元素的坐标,判断点击元素与监听目标的坐标是否相交触发记录。ui

判断点击位置与元素是否相交方法: this

下面为实现代码spa

// 小程序监听页面点击,用户的点击行为都会执行elementTracker方法
<view catchtap='elementTracker'>
  <view class='buy-now'>
     <button bindtap='buy'>当即购票</button>
  </view>
</view>

// js 
elementTracker(clickInfo) {
  // 须要记录元素的className
  const trackElementName = '.more';
  // 经过元素坐标信息与点击坐标信息,判断是否被点击
  this.getBoundingClientRect(trackElementName).then((res) => {
    res.boundingClientRect.forEach((item) => {
      const isHit = this.isClickTrackArea(clickInfo, item, res.scrollOffset);
      console.log(isHit, 'isHit')
    });
  });
},
/**
 * 判断点击是否落在目标元素
 * @param {Object} clickInfo 用户点击坐标
 * @param {Object} boundingClientRect 目标元素信息
 * @param {Object} scrollOffset 页面位置信息
 * @returns {Boolean} 是否被点击
 */
isClickTrackArea(clickInfo, boundingClientRect, scrollOffset) {
  if (!boundingClientRect) return false;
  const { x, y } = clickInfo.detail; // 点击的x y坐标
  const { left, right, top, height } = boundingClientRect;
  const { scrollTop } = scrollOffset;
  if (left < x && x < right && scrollTop + top < y && y < scrollTop + top + height) {
    return true;
  }
  return false;
},
/**
 * 获取页面元素信息
 * @param {String} element 元素class或者id
 * @returns {Promise}
 */
getBoundingClientRect (element) {
  return new Promise((reslove) => {
    const query = wx.createSelectorQuery();
    query.selectAll(element).boundingClientRect();
    query.selectViewport().scrollOffset();
    query.exec(res => reslove({ boundingClientRect: res[0], scrollOffset: res[1] }));
  });
}
复制代码

二、扩展Page方法

因为elementTracker方法须要在Page中定义以供wxml调用,若是每一个页面手动编写就过于繁琐了,能够经过改写Page来实现自动扩展,代码以下code

// 记录原Page方法
const originPage = Page;
// 重写Page方法
Page = (page) => {
  // 给page对象注入三个方法
  page.elementTracker = function() {}
  page.methodTracker = function() {}
  page.isClickTrackArea = function() {}
  return originPage(page);
};
复制代码

三、对页面函数埋点

有些场景咱们除了对页面元素点击埋点,还要对页面函数进行埋点,例如用户下拉刷新的时候,能够对原方法进行包装,插入埋点代码,方案和第三点差很少。

const originPage = Page;
// 重写Page方法
Page = (page) => {
  // 给onShow方法插入埋点
  const originMethod = page['onShow'];
  page['onShow'] = function() {
    report() // 记录埋点
    return originMethod();
  }
  return originPage(page);
};
复制代码

四、经过配置表设置埋点

上面介绍了页面元素和函数的埋点方式,下面讲一下如何管理埋点信息解决代码入侵问题,能够把埋点信息以配置表的方式声明,之后还能够作到动态配置,在服务端配置完毕下发到客户端。

const tracks = {
  path: 'pages/film/detail',
  elementTracks: [
    {
      element: '.buy-now',  // 声明须要监听的元素
      dataKeys: ['film.filmId'], // 声明须要获取Data下的film对象下的filmId字段
    },
    methodTracks: [
    {
      method: 'toBannerDetail', // 声明须要监听的函数
      dataKeys: ['imgUrls'], // 声明须要获取Data下的imgUrls数据
    },
  ],
  ]
};
复制代码

最后

完整的代码已经封装成SDK了,能够快速集成到项目 github地址

相关文章
相关标签/搜索