數據埋點是監控用戶在應用中的表現行爲,對於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、開源做品: