前言
小程式由於封閉性較強,要像web應用一樣實現靈活的資料收集,會有一定難度。目前開源的埋點SDK,一般採用手動埋點的方式,這種方式有較強的侵入型,為了解決這個問題就有了該文章。
手動埋點
以騰訊移動分析的SDK為例,如果要記錄埋點資訊,只要插入一句程式碼即可
// 例如,記錄搜尋行為search(keyword) {
if (keyword) {
...業務程式碼
} mta.Event.stat("ico_search", {"query":keyword
});
}複製程式碼
示例程式碼看起來是比較簡潔的,但是埋點需要收集的資料往往不是單一的,複雜的埋點程式碼插入業務程式碼,會影響程式碼的閱讀體驗,而且埋點程式碼散落在各個地方,不方便管理。
由於手動埋點必須插入到函式中,有時候我們為了獲取頁面某一元素點選資訊,產生了一種叫無業務相關埋點,簡單來說就是你的函式定義,就只有埋點程式碼,當這種埋點頻繁出現,程式碼會被嚴重汙染。
// wxml<
view bindtap="track">
這只是一個展示view<
/view>
//js track() {
mta.Event.stat("eleClick", {"name":xxxxx
});
}複製程式碼
另外,由於PM會頻繁調整埋點資訊,而埋點是一個繁瑣又無聊的工作,基於Don’t Repeat Yourself 原則,手動埋帶要不得。
總結以上,手動埋點有下列問題
- 影響程式碼的閱讀體驗
- 埋點程式碼散落在各個地方,不方便管理
- 程式碼會被汙染
- 埋點是一個繁瑣又無聊的工作
自動埋點
實現思路:監聽使用者點選–>
讀取埋點配置JOSN,判斷是否需要上報–>
上報資料
1、小程式監聽使用者點選行為
web應用監聽使用者點選行為是比較容易,但是小程式沒有提供Dom的事件監聽,不過我們可以通過事件冒泡的方式捕獲。
// web監聽頁面點選document.addEventListener('click',(e) =>
{console.log(e)
})// 小程式監聽頁面點選,使用者的點選行為都會執行elementTracker方法<
view catchtap='elementTracker'>
<
view class='buy-now'>
<
button bindtap='buy' animation="{{scaleAnim
}
}">
立即購票<
/button>
<
/view>
<
/view>
複製程式碼
2、判斷點選位置是否落在監聽元素中
假設需要監聽使用者是否點選class為buy-now元素,可以通過獲取buy-now元素長寬,定位和點選位置座標判斷是否出現重疊,以判斷是否被點選。
/** * 判斷點選是否落在目標元素 * @param {Object
} clickInfo 使用者點選座標 * @param {Object
} boundingClientRect 目標元素資訊 * @param {Object
} scrollOffset 頁面位置資訊 * @returns {Boolean
} */export const isClickTrackArea = function (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;
};
複製程式碼
3、通過配置表宣告埋點
為了解決程式碼入侵問題,可以將所有埋點資訊統一管理,通過配置表的方式,除了方便管理,以後還可以做到動態配置,在服務端配置完畢下發到客戶端。
const tracks = {
path: 'pages/film/detail', elementTracks: [ {
element: '.buy-now', // 宣告需要監聽的元素 dataKeys: ['film.filmId'], // 宣告需要獲取Data下的哪些資料
}, ]
};
複製程式碼
4、對頁面函式埋點
有些場景我們除了對頁面元素點選埋點,還要對頁面函式進行埋點,例如使用者下拉重新整理的時候,可以對原方法進行包裝,插入埋點程式碼。
rewritePage() {
const originPage = Page;
Page = (page) =>
{
Object.keys(page).forEach((methodName) =>
{
// 執行埋點邏輯 typeof page[methodName] === 'function' &
&
this.recordPageFn(page, methodName);
});
// 執行原Page物件 return originPage(page);
};
}複製程式碼
最後
完整的程式碼已經封裝成SDK了,可以快速整合到專案github.com/zhengguoron…