老大喊我做一个项目埋点方案,我给他这么搞,做前端的都用得上!
作者:vannvan
来源:SegmentFault 思否社区
众所周知,做C端产品对用户体验的要求是极高的。同时产品实施是否到位,投入回报是否成正比,成了一个团队是否有奖励的关键因素(这是一个最实际的软件团队的真实诉求“之一“哈哈哈)。尽管前期会做众多的用户调研,收集收据等等,明确哪些是用户基础需求,哪些是用户兴奋需求,但还是需要一个具体的可以量化的数据支撑,来评估某项业务是否满足了用户真实的需求,以及为产品后期迭代做参考等等。
那么基于以上的实际情况,对于整个产品线而言,做一个埋点业务收集是非常必要的。当然做埋点还有更多的意义,在这里暂不展开讨论。
以下将对该方案实施过程进行全面的分析,同时也将提供一个简单的合理的可复用的方案输出,感兴趣的客官请留步~✌
当前现状
目前3个产品业务线产品,对于前端项目而言是分开管理的,现有业务也会有源源不断的需求增加,后面还会增加新的产品线。
主要使用
Vue.js@2.0
版本,但有一个项目是采用3.0
版本开发的。项目已开发迭代历经8个月,主要产品业务代码已超17万行。
整体分析
对接第三方没有可以既可以满足当下需求,又可以满足强扩展性的关键要素的现成方案,同时对于隐私信息的收集不能交给第三方。
现有代码量不具备可精准卖点的条件。
pv类型的数据收集可暂时交给某度统计,这种大而笼统的数据只有运营会关注,埋点对用户分析的粒度更小。
埋点尽量不影响具体业务功能及代码,甚至绝对的不影响。
实际需求
收集粒度到按钮级别的用户。
页面进入时间,停留时间,也就是要拿到
enterTime
和leaveTime
。要具备可对某
页面
使用量,某按钮使
用量,某用户使用轨迹
,某时间段
按钮使用量,用户浏览器
基本信息,后台最好具备前端页面功能点击量的可视化
还原。
把需求转换成数据
userAgent // 浏览器信息,包含设备信息,分辨率等
path // 访问页面 可以用router也可以用location.href
pageInfo // 页面信息 enterTime和leaveTime
userInfo // 用户信息 当前登录用户个人信息
eventData // 操作事件信息 事件类型,操作DOM节点,操作时间,节点名称(html节点名称),节点文本
代码怎么下手
不影响现有业务,抽离成公共类是必须的。
用户信息以及其他后期可能记录的属于扩展性信息,应可以外部传入。
目前使用开源UI框架,项目整体
按钮
节点都是button
标签(部分不是的可以改过来)。数据记录和发送,发送不能太频繁,需要一个记录数据的队列,设定一个阈值,到达阈值后进行发送并清空。
代码大概的雏形
class Monitor {
constructor() {
}
/**
* @description 初始化方法:
* extentData 用于传入基于业务的数据信息,
* router 是vue-router对象,这里既可以通过init传入,也可以在当前类模块直接引入,
* config 是配置信息
* @param {*} { extentData = null, router = null, config = {} }
* @memberof Monitor
*/
init({ extentData = null, router = null, config = {} }) {
//TODO
// 这里可以做一些覆盖默认配置,初始化监听事件等操作
let { vpt } = config
this.vpt = vpt ? vpt : this.vpt
this.uaHandler()
// 这里下面会讲
this.eventHandler = this.eventCallback.bind(this) // 关键
document.addEventListener('click', this.eventHandler, true)
}
}
// 这里建议在项目封装的router管理模块使用
import Monitor from './monitor'
const monitor = new Monitor()
monitor.init({
router: router,
extentData: {
userInfo: {
userName:"张三",
account:"13666666666"
}
}
})
Monitor
类应具备的数据 constructor() {
// 发送队列的阈值
this.vpt = 10
// 事件节点类型限制
this.limitNodeType = ['button']
// 用户浏览器信息
this.uaInfo = {}
// 页面级别的数据队列
this.pageDataQuene = []
// 当前操作队列ID
this.currentQueneId = null
// 此属性用于保存bind返回的匿名函数
this.eventHandler = null
}
埋点功能结构
/**
* @description ua信息记录
* @memberof Monitor
*/
uaHandler() {
this.uaInfo = {
userAgent: navigator.userAgent,
dpiWidth: window.screen.width,
dpiHeight: window.screen.height
}
}
guid
用于标识”当前页面“
确保唯一性,guid
生成方法如下,一般在阈值内可保证唯一性,没必要搞得太复杂。/**
* @description 生成guid,当前操作队列的唯一标识
* @returns {*}
* @memberof Monitor
*/
guid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = (Math.random() * 16) | 0,
v = c == 'x' ? r : (r & 0x3) | 0x8
return v.toString(16)
})
}
get()
方法用于获取数据,clear()
用于清空数据/**
* @description 用于外部获取操作队列
* @returns {*} Array[]
* @memberof Monitor
*/
get() {
return this.pageDataQuene
}
/**
* @description 用于清空队列
* @memberof Monitor
*/
clear() {
//TODO
this.pageDataQuene = []
}
Monitor
处理,这里仅需在内部同时监听队列即,如是可以有vptHandler
方法/**
* @description 阈值监听,达到阈值就发送数据
* @memberof Monitor
*/
vptHandler() {
if (this.pageDataQuene.length >= this.vpt) {
this.sendData() // 这里用于走上传数据业务,上传完毕后清空数据,可根据实际情况进行处理
}
}
router.afterEach(async (to) => {
// 离开监听
this.updateLeaveTime()
// 阈值监听
this.vptHandler()
// 当前操作页面的唯一标识
this.currentQueneId = this.guid()
let initPageData = [
{
id: this.currentQueneId,
path: to.path, // 因为当前项目目录结构和菜单路由命名是高度一致的,所以可以采用path进行记录
uaInfo: this.uaInfo,
pageInfo: {
entryTime: this.getTime() //注意这里只有enterTime,更新leaveTime的时机交给
关注公众号:拾黑(shiheibook)了解更多
赞助链接:
关注数据与安全,洞悉企业级服务市场:https://www.ijiandao.com/
四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/
随时掌握互联网精彩
- 123云盘内容付费和打赏的平台抽成比例是多少?
- 美元兑人民币汇率2023年12月25日
- 欧元人民币汇率2023年5月26日
- 科大讯飞回应薪酬回溯制度;OpenAI宣布开放API,开发人员可将ChatGPT集成到自己产品;Godot 4.0发布|极客头条
- 【杂谈快报】中国电信将与Conflux合作在香港试行支持区块链的SIM卡;传腾讯XR团队全线解散
- 本周大新闻|Khronos组建元宇宙标准联盟,传腾讯正式设立XR部门
- 腾讯全面上云背后:程序员的技术焦虑和技术理想
- 数万人在线听课!同心信创大讲堂火爆全国170余所院校
- “提前还了150万房贷”,是赚还是亏?
- 中兴通讯选举李自学为董事长,续聘徐子阳为总裁
- 三星微软“哥俩好”,或联手开发ARHoloLens
- 以前不装杀毒软件就是“裸奔”,那现在呢?