作者 | 蟹老板
责编 | 伍杏玲
小程序由于封闭性较强,如果要像Web一样实现灵活的数据收集,会有一定难度。目前开源的埋点SDK,一般采用手动埋点的方式。
这种方式有较强的侵入型,同时开发成本较高,下面我们来讨论下如何解决这个难题。
手动埋点
以腾讯移动分析的SDK为例,如果要记录埋点信息,只要插入一句代码即可:
// 例如,记录搜索行为
search(keyword) {
if (keyword) {
...业务代码
}
// 埋点代码
mta.Event.stat("ico_search", {"query":keyword});
}
示例代码比较简单,但由于埋点需要收集的数据往往不是单一的。在现实开发里很多复杂的埋点代码插入业务代码,不仅会影响代码的阅读体验,而且埋点代码散落在各个地方,不方便管理,有时候还会整出Bug来。
由于手动埋点必须插入到函数中,有时候我们为了获取页面某一元素点击信息,产生了一种叫无业务相关埋点,简单来说就是你的函数定义的只有埋点代码,当这种埋点频繁出现,代码会被严重污染。
// wxml
<view bindtap="track">这只是一个展示view</view>
//js
track() {
mta.Event.stat("eleClick", {"name":xxxxx});
}
另外,PM会频繁调整埋点信息,基于Don't Repeat Yourself 原则,我们尽量避免手动埋点。总结下,手动埋点有下列问题:
影响代码的阅读体验
埋点代码散落在各个地方,不方便管理
代码会被污染
-
埋点是一个繁琐又无聊的工作
自动埋点
1、通过事件冒泡监听元素是否被点击
小程序没有提供Dom的事件监听方法,不过我们可以通过事件冒泡的方式监听。在WXML最外层绑定catchtap事件获取点击元素的坐标,判断点击元素与监听目标的坐标是否相交,然后触发记录。
判断点击位置与元素是否相交方法:
代码如下:
// 小程序监听页面点击,用户的点击行为都会执行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] }));
});
}
2、扩展Page方法
由于elementTracker方法需要在Page中定义以供WXML调用,如果每个页面手动编写就过于繁琐了,可以通过改写Page来实现自动扩展,代码如下:
// 记录原Page方法
const originPage = Page;
// 重写Page方法
Page = (page) => {
// 给page对象注入三个方法
page.elementTracker = function() {}
page.methodTracker = function() {}
page.isClickTrackArea = function() {}
return originPage(page);
};
3、对页面函数埋点
有些场景除了对页面元素点击埋点,还要对页面函数进行埋点,例如用户下拉刷新的时候,可以对原方法进行包装,插入埋点代码,方案和第2点差不多。
const originPage = Page;
// 重写Page方法
Page = (page) => {
// 给onShow方法插入埋点
const originMethod = page['onShow'];
page['onShow'] = function() {
report() // 记录埋点
return originMethod();
}
return originPage(page);
};
4、通过配置表声明埋点
那么如何管理埋点信息,来解决代码入侵问题呢?可以把埋点信息以配置表的方式声明,以后还可以做到动态配置,在服务端配置完后下发到客户端。
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下载。
作者简介:蟹老板,一个喜欢研究数据与交互的前端开发
代码地址:https://github.com/zhengguorong/xbosstrack-wechat
原文链接:https://juejin.im/post/5c4840196fb9a04a05400474
声明:本文为作者投稿,版权归对方所有。
热 文 推 荐
☞有赞公开强推 996 制,员工:已拨打市长电话
☞程序员有话说 | 我成了敲代码的“佛教徒”
☞小心!你的脸正在成为色情片主角
☞鏖战九载,Google 是否会因 Oracle 而弃用 Java?
☞iPhone曝严重漏洞,用户接听FaceTime前或被“监听”!
☞聊聊云计算:为什么构建网站时常会用到负载均衡
☞年度大戏!以太坊大神怒怼智能合约之父,尼克·萨博到底做错了啥?
☞嫁人当嫁程序员
print_r('点个好看吧!');
var_dump('点个好看吧!');
NSLog(@"点个好看吧!");
System.out.println("点个好看吧!");
console.log("点个好看吧!");
print("点个好看吧!");
printf("点个好看吧!");
cout << "点个好看吧!" << endl;
Console.WriteLine("点个好看吧!");
fmt.Println("点个好看吧!");
Response.Write("点个好看吧!");
alert("点个好看吧!")
echo "点个好看吧!"
点击“阅读原文”,打开 CSDN App 阅读更贴心!
喜欢就点击“好看”吧
请发表评论