首先,先看看埋点能做什么?
-
采集用户行为
- 页面的pv/uv
- 用户在页面的停留时长
- 用户的访问链路
- 用户的交互行为
- 营销模块的曝光数据
- 用户的设备信息等
-
- 首屏加载时长
- 白屏时间
- 小程序运行异常
- http接口异常
- 脚本异常1. 采集用户行为
埋点分类及对比
言归正传
本期主要内容:在微信小程序中通过无埋点的方式收集上报用户行为;
一、通过拦截小程序app和page的生命周期来采集用户的pv、uv、停留时长、及访问链路;
拦截的目的是什么?
答:进行拦截之后,小程序生命周期在执行时,可以顺带执行我们的埋点收集和上报的程序。
因此,
我们不能干扰开发者定义的生命周期方法,要让我们的埋点程序在开发者无感知的情况下执行。
怎么实现?
1.对App,Page,Component三个方法进行重写。
cnost init = () => {
const oldApp = App;
const oldPage = Page;
const oldComponent = Component;
/**
*options 是开发者对App方法的传参
*options={
* onLaunch(){ .... }
* }
**/
App = function(options){
//拦截options中的生命周期方法,以拦截onLaunch方法为例,
// options['onLaunch'] = function(){ ...此处是拦截方法... }
//执行开发者传入的逻辑
oldApp(options)
}
// ....同理, Page 和 Component 也是同样操作....
}
2.拦截的核心逻辑
/**
* 页面生命周期拦截
* @param {*} options
* @param {*} key
* @param {*} callback
* @param {*} isIntercepted
* @returns
*/
const interceptor = function(options, key, callback, isIntercepted){
if(!isIntercepted){
// 是否进行拦截,不拦截直接return
return;
}
if(options&&options[key]&&typeof options[key] === 'function'){
const fn = options[key];
options[key] = function(args){
// 执行拦截逻辑
callback.call(this, args);
// 执行开发者自定义的生命周期方法
return fn.call(this, args);
}
}else{
options[key] = function(args){
return callback.call(this, args);
}
}
}
3.在init中使用拦截器
init = ()=>{
const oldApp = App;
const oldPage = Page;
const oldComponent = Component;
App = function(options){
interceptor(options, 'onLaunch', callback, _config['appOnLaunch']);
oldApp(options);
}
......
}
4.定义拦截逻辑
import Report from "./report.js"
// 上报
let report = null;
//保存配置
let _config = {};
class Tracker {
constructor(config){
const defConfig = {
'appName': '',
'url': '',
'appOnLaunch': true,
'appOnShow': true,
'appOnHide': true,
'pageOnLoad': true,
'pageOnShow': true,
'pageOnHide': true,
'pageOnUnload': true,
'reportTime': 2000, //上报时间间隔,
'pageConfig':{},
'componentConfig':{},
}
_config = Object.assign(defConfig, config);
// 初始化上报方法
report = new Report(_config.reportTime);
this.report = report;
this.init();
}
// APP生命周期拦截回调
app = {
onLaunch(args){
console.log('#tracker: app launch', args)
//上报数据
report.push({ name: 'app', event: 'APP_ON_LAUNCH', view:'app', type: 'appload' })
},
......
}
// Page生命周期拦截
page = {
onLoad(args){
console.log('#tracker: page load', args)
//上报数据
report.push({ name: 'page', event: 'PAGE_ON_LOAD', view: 'page', type: 'load' })
},
......
}
// 组件生命周期拦截
component = {
attached(){
handleComponentConfig.call(this);
}
}
init = ()=>{
const oldApp = App;
const oldPage = Page;
const oldComponent = Component;
const _app = this.app;
const _page = this.page;
const _component = this.component;
App = function(options){
interceptor(options, 'onLaunch', _app.onLaunch, _config['appOnLaunch']);
}
Page = function(options){
interceptor(options, 'onShow', _page.onShow, _config['pageOnShow']);
oldPage(options)
}
Component = function(options){
//组件的生命周期在lifetimes中,拦截器略有不同
compLifetimeInterceptor(options, 'attached', _component['attached']);
oldComponent(options)
}
}
}
小结:
通过对App,Page的生命周期进行拦截,可以采集pv,uv, 用户停留时长,页面加载时长等,也可以捕获用户的页面访问链路。
二、通过拦截事件行为来采集用户行为,以点击事件为例
常用的实现方法:在页面的最外层元素上添加代理事件,对所有点击事件进行拦截。
缺点:
1.无法捕获到catch掉的事件,也无法捕获到组件中的点击事件;
2.会捕获到大量无用事件,造成大量无用数据的上报;
我的思路:使用配置文件的方式在需要埋点的页面,配置需要拦截的事件即可。
配置文件结构
export const pageConfig = {
//页面路径作为配置项的key
'pages/index/index':{
name: '首页', //页面名称
elements:[ //配置项元素,是一个数组
{
method: 'bindViewTap', //需要拦截的事件
type:'click', //事件类型,click代表点击事件
dataset:['nickname'], //需要采集的数据
},
]
},
}
//组件的事件配置
export const componentConfig = {
'components/myTest/myTest':{
name: '测试组件',
elements: [
{
method: 'btnTap',
type: 'click',
dataset:[ 'test' ]
}
]
}
}
核心拦截方法
// 点击事件拦截处理
const clickMethodProxy = (_this, el, action)=>{
// 点击事件
const methodName = el.method; //需要拦截的事件名称
const methodFn = _this[methodName]; //开发者自定义的事件回调
// 点击事件拦截
_this[methodName] = function(e){
//执行开发者自定义的拦截方法
methodFn.call(_this, e);
//采集需要上传的数据
const dataset = e.currentTarget.dataset;
const extraData = mapExtraData(dataset, el.dataset||[])
//数据上报
report.push({ page: action.path, pageName: action.name, event: methodName, view: 'element', type: 'click',extraData } )
}
}
小结:
通过配置文件的方式对指定的事件进行拦截来实现埋点上报,方便统一管理和维护,且对业务代码基本没有干扰。
三、借用interscetionObserver实现对曝光数据的采集
什么是intersectionObserver?传送门: developer.mozilla.org/zh-CN/docs/… 下面是简单的示意图:
曝光的实现逻辑相对简单,读者可以自行思考实现。^-^ ^-^ 这里还有一个坑,小心动态渲染的曝光元素,不做特殊处理是监听不到的
声明:本文仅供个人学习使用,来源于互联网,本文有改动,本文遵循[BY-NC-SA]协议, 如有侵犯您的权益,请联系本站,本站将在第一时间删除。谢谢你
原文地址:略干,写一套小程序无埋点SDK