小程序從手動埋點到自動埋點

前言

小程序因爲封閉性較強,要像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地址

相關文章
相關標籤/搜索