数据埋点是监控用户在应用中的表现行为,对于TO C的产品迭代来讲愈来愈重要。前端
数据埋点是产品需求分析的来源,检验功能是否达到预期。前端是更贴近用户,我来讲说数据埋点在系统开发中的方案。vue
不一样的产品对于数据的关注的角度不一样,根据需求来采集和设计不一样的方案。好比信息流的产品抖音,关注用户的停留时间更高。好比商品类的注重的是“复购率”,统计新老用户。node
数据埋点统计一般分为:mysql
(1)页面访问量统计ios
(2)功能点击量统计git
咱们今天只讨论页面访问量统计,在开发系统中本身定义页面访问量相关数据的统计。github
一般咱们接入的是第三方的服务,好比百度统计,就有相关页面访问统计,以及用户的画像等等。可是做为开发人员来讲,若是在本身作的系统中,按照本身的需求定制化数据埋点是否是很cool。web
一、页面访问量相关统计redis
页面访问量一般分为:PV和UV。sql
(1)PV:页面访问人次。
(2)UV:页面访问人数。
页面访问量,并不是仅仅是内容吸引力决定的,影响因素有:入口,页面位置,到主页面深度等等。入口主要是UI视觉相关人员设计。入口位置能够经过数据分析后进行调整,到主页面深度能够分析用户的访问路径进行调整。
采集页面加载 from、to 以获知用户访问路径:
分析能够知道用户广泛访问深度,每一层和每个页面的流失率能够很直观看出来,从而调整核心页面入口源和深度。
还有一些特殊状况出现:好比PV稳定的页面访问量忽然暴跌,多是加载失败或者报错。
接下来我经过本身的系统接入数据埋点:https://chat.chengxinsong.cn
技术架构:vue+vuex+koa2+mysql+websocketIO+redis等。
在main.js中全局定义
/*全局PV统计*/ router.beforeEach((to, from, next) => { let flag = localStorage.getItem("HappyChatUserInfo") !== null ? true: false; let data = { type: 'visit', user_id: flag ? JSON.parse(localStorage.getItem("HappyChatUserInfo")).user_id: '获取不到userId', time: (new Date()).getTime(), params: { from: { name: from.name || '', path: from.path || '', query: from.query || '' }, to: { name: to.name || '', path: to.path || '', query: to.query || '' } } } App.methods.logEvent(data); next() })
停留时间能够经过from和to页面的时间(跳转页time - 当前页time)。关闭应用的时候如何统计?能够考虑window.onunload方法
window.onunload = function unloadPage() { let data = { type: 'close', user_id: localStorage.getItem("HappyChatUserInfo") !== null ? JSON.parse(localStorage.getItem("HappyChatUserInfo")).user_id: '获取不到userId', time: (new Date()).getTime(), params: { from: { name: '关闭前', path: router.currentRoute.path || '', query: router.currentRoute.params || '' }, to: { name: '关闭', path: '', query: '' } } } App.methods.logEvent(data); }
这时候咱们须要去定义接口传参,接口方法是logEvent。
咱们自定义Vue插件App的method,用于埋点数据向服务器发送。
咱们在App.vue中定义
具体方法
/* 数据埋点 */ logEvent(opts) { let data = { type: opts.type, user_id: opts.user_id, time: opts.time, params: opts.params || {} } return Api.pvLog(data).then(res => { console.log(res) }).catch(function (error) { console.log(error); }); }
其中Api是axios的接口统一封装的方法。
数据到了后端怎么保存,保存哪些参数,根据需求来定义,好比常见的:客户端IP,数据类型type,用户id,访问时间,from中的页面名字name,路径path,查询茶树query等等。
后端接口的控制层。(接口需不须要验证,根据需求来设计。)
let pvLog = async (ctx, next) => { const data = ctx.request.body; let req = ctx.req; let clientIP = req.headers['x-forwarded-for'] || req.connection.remoteAddress || req.socket.remoteAddress || req.connection.socket.remoteAddress; userModel.logPV([clientIP, data.type, data.user_id, data.time, data.params.from.name || '', data.params.from.path || '', JSON.stringify(data.params.from.query) || '', data.params.to.name || '', data.params.to.path || '', JSON.stringify(data.params.to.query) || '']); ctx.body = { success: true } };
接下来就是数据入库操做,代码就不放了,源码地址:
一、后端代码:https://github.com/saucxs/hap...
二、前端代码:https://github.com/saucxs/hap...
欢迎fork和start。
虽然官方说,慎用全局混入对象。
放一下示例代码
import Vue from 'vue' Vue.mixin({ beforeRouteEnter (to, from, next) { next(vm => { vm.$app.logEvent({ type: 'visit', name: to.name, time: new Date().valueOf(), params: { from: { name: from.name, path: from.path, query: from.query }, to: { name: to.name, path: to.path, query: to.query } } }) }) }, beforeRouteLeave (to, from, next) { this.$app.logEvent({ type: 'visit', name: to.name, time: new Date().valueOf(), params: { from: { name: from.name, path: from.path, query: from.query }, to: { name: to.name, path: to.path, query: to.query } } }) next() } })
咱们须要考虑是否在应用关闭的时候触发beforeRouteLeave方法?
还有两个问题:
(1)每个页面都有钩子函数beforeRouteEnter,beforeRouteLeave方法,如何进行合并。
(2)有时候涉及到子路由问题,子路由的页面会调用2次beforeRouteEnter和beforeRouteLeave方法,PV会翻倍。
因此以为方案二仅供参考,慎用。
其中,this.$app.logEvent(vm.$app.logEvent)等同于方案一的App.logEvent。
根据实际需求和评估使用不一样的方案:
(1)SPA应用,单入口,在入口文件全局定义Router.beforeEach就能够,就是方案1。
(2)MPA应用,多入口,能够封装公用的逻辑,免去重复构造entry成本。
(3)SPA+MPA混合应用:采用MPA方案就行。
(4)SSR应用:追求SEO采用服务端渲染(SSR),采用不一样的模板渲染页面,直接统计调用模板的次数就能够知道PV相关数据。
至于 UV,统计 PV 时采集 userId 去重便可。若应用无用户管理体系,采集 IP、deviceId 也可粗略得知 UV(不精准)。
做者简介
昵称:saucxs | songEagle | 松宝写代码
github:https://github.com/saucxs
1、技术产品
2、开源做品: