如何在微信小程序中实现一个手动埋点和自动埋点功能
如何在微信小程序中实现一个手动埋点和自动埋点功能?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。
一、手动埋点
手动埋点就是在每一处需要的地方,都加一段上报埋点的代码。影响代码的阅读体验,且散落的埋点代码不方便管理。以页面 pv 为例,我们此前是在每一个页面中上报 pv:
//src/manual/home/index.tsx importtrackingfrom"./tracking"; //pageSn是前端和产品约定的「页面在埋点系统的唯一标识」,比如这个项目首页的标识符是数字11664 constpageSn=11111; exportdefault()=>{ //useDidShow是Taro专有的Hook,等同于小程序原生componentDidShow生命周期,会在页面展示的时候调用。 useDidShow(()=>{ //通过统一封装的sendPv方法发送pv埋点 sendPv(pageSn); }); return<View>手动埋点页面</View>; };
二、自动埋点
自动埋点可分为全自动埋点和半自动埋点。全自动埋点则是不管需不需要,将所有的点都埋了。前端肯定开心了 “以后埋点产品都不要不要找我啦”,可数据同学就哭唧唧了。
比如,腾讯和 Taro 团队共同推出 腾讯有数自动化埋点,接入超级简单。比如配置 proxyPage 为 true 即可 “上报所有页面的 browse 、leave、share 等事件”,配置 autoTrack 为 true 即可 “自动上报所有元素的 tap、change、longpress、confirm 事件”。
可从数据量和有效性来说,「全埋」等于「不埋」,因为「全埋」一方面对数据存储量要求很高,另一方面会给我们负责数据清洗的同学带来大量工作。
所以接下来,还是从中寻求平衡,着重看半自动埋点。
1、页面曝光(pv)
页面曝光(pv),理想的上报方式是:
在一个统一的地方(如 trackingConf.ts),配置好每个要埋点的页面的标识符(即 pageSn)页面显示后,自动判断下是否需要上报(是否在 trackingConf.ts 配置文件中),要就直接上报。
具体实现
(1)统一配置埋点字段,pageSn 表示页面在埋点系统中的标识符
//trackingConf.ts exportdefault{ "auto/home/index":{ pageSn:11111, }, };
当然,如果你的业务允许三七二十一,上报所有页面 pv(带上 path 让产品自己筛选),那(1)这步可以省了,直接看(2),这种方式可称为「pv 全自动埋点」。
(2)封装 usePv hook,在页面展示时,获取当前页面 pageSn、判断是否要埋 pv、要的话发送 pv
//usePv.ts //获取当前页面path,借助Taro的getCurrentInstance exportconstgetPath=()=>{ constpath=Taro.getCurrentInstance().router?.path||""; //去掉开头的/,比如将'/auto/home/index'改为'auto/home/index' returnpath.match(/^\/*/)?path.replace(/^\/*/,""):path; }; //获取当前页面pageSn、判断是否要埋pv、要的话发送pv //入参getExtra支持携带额外参数 constusePv=({ getExtra, }:{ getExtra?:()=>any; }={})=>{ //页面曝光 useDidShow(()=>{ constcurrentPath=getPath(); //从trackingConf中获取pageSn constpageSn=trackingConf[currentPath]?.pageSn; console.log("自动获取pageSn",currentPath,pageSn); if(pageSn){ constextra=getExtra?.(); //通过统一封装的sendPv方法发送pv埋点 extra?sendPv(pageSn,extra):sendPv(pageSn); } }); };
(3)然后封装页面组件 WrapPage ,使用上述的 usePv():
importReactfrom"react"; import{View}from"@tarojs/components"; importusePvfrom"./usePv"; functionWrapPage(Comp){ returnfunctionMyPage(props){ usePv(); return( <View> <Comp{...props}/> </View> ); }; } exportdefaultWrapPage;
(4)最后在所有页面组件,包一层 WrapPage 即可实现「所有页面按需埋点」:
//src/auto/home/index.tsx constIndex=WrapPage(()=>{ return<View>自动埋点页面</View>; });
后续新开发一个页面,除了用 WrapPage 包裹外,只需要在第(1)步的 trackingConf.ts 中增加该页面的 pageSn 即可。
提问环节
好奇宝宝们可能要问了:
(1)WrapPage 里这样封装了 usePv(),应该如何支持上报自定义字段呢?举个例子,产品希望 src/auto/home/index.tsx 这个页面上报 pv 的时候,额外上报一下 当前页面 URL 查询参数即 params。很简单,就是这个页面不要用 WrapPage 包裹,而是拿到 params 后直接调用 usePv 函数:
//src/auto/home/index.tsx constIndex=()=>{ usePv({ getExtra:()=>{ constparams=Taro.getCurrentInstance().router?.params; return{params}; }, }); return<View>自动埋点页面</View>; });
(2)这里每个页面组件,都要用 WrapPage 包裹一下,对业务还是有侵入型了,原生小程序可以改写 Page,在 Page 中直接 usePv()。Taro 项目应该也可以这么做,实现 0 业务侵入吧?
Taro 项目中,确实可以也可以和原生小程序一样,在 App 中统一拦截原生 Page,但这样的话,上面「某些页面要计算额外参数并上报」就不好解决了。
2、页面分享
微信小程序中,存在两种分享:
分享给好友:useShareAppMessage。
分享到朋友圈:useShareTimeline。小程序基础库 v2.11.3 开始支持,目前只在 Android 平台可用。
具体实现
以 useShareAppMessage 为例(useShareTimeline 同理):(1)仍在 trackingConf.ts 统一配置文件中,增加分享埋点的标识字段 eleSn (及额外参数)
//trackingConf.ts exportdefault{ "auto/home/index":{ pageSn:11111, shareMessage:{eleSn:2222,destination:0},//增加shareMessage包含分享好友的eleSn、业务额外参数destination } };
(2)封装 useShareAppMessage 方法,业务调用 Taro.useShareAppMessage 的地方全局替换为这个 useShareAppMessage。
//分享给好友,统一埋点 exportconstuseShareAppMessage=( callback:(payload:ShareAppMessageObject)=>ShareAppMessageReturn )=>{ letnewCallback=(payload:ShareAppMessageObject)=>{ constresult=callback(payload) constcurrentPath=getPath();//getPath获取当前页面路径,可参考「1、页面曝光(pv)」中的getPath //从trackingConf中获取pageSn、shareMessage等 const{pageSn,shareMessage}=trackingConf[currentPath] const{eleSn,...extra}=shareMessage||{} letpage_el_sn=eleSn const{imageUrl:image_url,path:share_url}=result const{from:from_ele}=payload constreportInfo={ from_ele, share_to:'friend',//'friend'表示分享给好友 image_url, share_url, ...extra } console.log('...useShareAppMessagetracking',{pageSn,page_el_sn,reportInfo}) sendImpr(pageSn,page_el_sn,reportInfo)//可自行封装sendImpr方法,发送分享埋点信息 returnresult } Taro.useShareAppMessage(newCallback) }
这样,如果有个页面需增加分享好友的埋点,直接在 trackingConf.ts 中增加 shareMessage 的 eleSn 即可,useShareTimeline 同理。
提问环节
好奇宝宝们可能要问了:页面需要增加分享好友/朋友圈的埋点,可否 0 配置(即不用修改上述的 trackingConf.ts 文件)?与前文中「pv 全自动埋点」类似,只要和产品约定好捞数据的方式也可以,比如笔者和产品约定了:每个页面分享好友/朋友圈,eleSn 都是 444444,然后产品通过 pageSn 判断是哪个页面,通过 share_to 判断是分享好友 / 朋友圈,对于分享好友的场景,再通过 from_ele 判断通过右上角分享还是点击页面中的按钮分享。这样页面分享也可以全自动埋点了。
3、元素埋点
元素自动埋点的调研遇到阻力,尚未落地。下文主要谈不同思路遇到的问题,有好的建议欢迎评论区沟通。
我们元素埋点,较高频的有曝光、点击事件,中低频的有滚动、悬停等事件。
手动埋点的方式就是在元素指定事件触发的时候,手动执行 sendImpr 上报埋点(带上页面唯一标识符 pageSn、 元素唯一标识符 eleSn)。
那这个环节是否可以省事一些呢?对业务无侵入,大概的做法还是:
在 Component 指定事件触发增加个 hook -> 判断是否要上报埋点 -> 满足条件则上报
问题一分为二:
(1)拦截元素事件回调
可以拦截并遍历小程序 Component 接收到的 options.methods,如果是一个自定义函数,则在函数被调用的时候判断第一个参数(假设命名为 e)的 type 是否等于 tap 等事件。这时候可以根据 e 等信息决定是否满足埋点上报条件了。原生小程序中的实现,大致如下:
//App.js App({ onLaunch(){ letold=Component Component=function(config){ //拦截业务传入的config constnewConf=proxyConfig(config) old(newConf) } } }) constproxyConfig=function(conf){ constmethods=conf.methods //获取自定义方法(按需排除一些不埋点的方法) letdiyMethods=Object.entries(methods).filter(function(method){ letmethodName=method[0] return![ "onLoad", "onShow", "onReady", "onHide", "onUnload", "onPullDownRefresh", "onReachBottom", "onPageScroll", "onShareAppMessage", "onResize", "onTabItemTap", "observer", ].includes(methodName); }) diyMethods.forEach(function(method){ const[methodName,methodFn]=method //修改conf中的methods methods[methodName]=function(...args){ conste=args&&args[0] if(e&&e.type==='tap'){ console.log('...tapping',methodName,args)//触发点击事件的时候,按需上报埋点 } methodFn.call(this,...args) } }); //返回修改后的conf returnconf }
Taro 项目中,不能直接在组件代码里用 Component,但可以迂回一些的方式实现相同目的,比如:
//myProxy.js module.exports=(function(){ letOriginPage=Page letOriginComponent=Component return(Page=function(conf){ conf.forEach(function(e){ let[methodName,methodFn]=e if(typeofmethodFn==='function'){ conf[methodName]=function(...args){ //做你想做的事,如改写conf等 methodFn.call(this,...args) } } }) returnOriginPage(conf) })( (Component=function(conf){ constmethods=conf.methods methods.forEach(function(e){ //做你想做的事,如改写conf等 }) OriginComponent(conf) }) ) })()
然后在 app.tsx 中直接引入 myProxy.js 即可
(2)如何自动生成元素唯一标识符
目前是通过埋点系统中申请下来的 eleSn 来唯一标识元素的,如果想要自动标识,可细分为:
XPath:在 pc / mobile 中还可以,但在小程序中不支持直接获取节点的 XPath / 根据 XPath 获取节点。微信小程序可否支持通过 XPath 获取 DOM 元素?
自动获取 组件方法名:原生小程序中,因为直接拦截了 Component options 中的 methods,所以在事件触发时可以获取到原始的方法名,但 Taro 项目中不行,因为 methods 被代理了一道,事件触发后,你看到的方法名都是 eh。
AST 解析源码分析出页面名、方法名和方法对应的注释来标识元素:Taro 项目中目测只能用这个方法,但成本较大,且「在代码不断迭代后,存量数据是否还能用」也是个问题,所以笔者未做尝试。
关于如何在微信小程序中实现一个手动埋点和自动埋点功能问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注恰卡编程网行业资讯频道了解更多相关知识。
推荐阅读
-
小程序时代,珠宝品牌如何拥抱微信生态
-
微信小程序如何实现走马灯式抽奖
-
微信小程序怎么实现tabBar底部导航
-
微信小程序怎么实现前台循环数据绑定
微信小程序怎么实现前台循环数据绑定本文小编为大家详细介绍“微信小程...
-
微信小程序中怎么实现swiper组件构建轮播图
-
微信小程序怎么授权获取用户详细信息
-
微信小程序如何使用蓝牙链接
微信小程序如何使用蓝牙链接这篇文章主要介绍“微信小程序如何使用蓝牙...
-
微信小程序怎么实现本地缓存数据增删改查功能
微信小程序怎么实现本地缓存数据增删改查功能这篇文章主要介绍“微信小...
-
微信小程序中怎么实现GET请求
-
微信小程序怎么实现下拉刷新界面
微信小程序怎么实现下拉刷新界面这篇文章主要介绍“微信小程序怎么实现...