【解決方案】數據埋點的一點思路與vue的SPA單頁面實踐

1、前言

數據埋點是監控用戶在應用中的表現行爲,對於TO C的產品迭代來講愈來愈重要。前端

數據埋點是產品需求分析的來源,檢驗功能是否達到預期。前端是更貼近用戶,我來講說數據埋點在系統開發中的方案。vue

2、數據埋點方案分析

不一樣的產品對於數據的關注的角度不一樣,根據需求來採集和設計不一樣的方案。好比信息流的產品抖音,關注用戶的停留時間更高。好比商品類的注重的是「復購率」,統計新老用戶。node

數據埋點統計一般分爲:mysql

(1)頁面訪問量統計ios

(2)功能點擊量統計git

咱們今天只討論頁面訪問量統計,在開發系統中本身定義頁面訪問量相關數據的統計。github

一般咱們接入的是第三方的服務,好比百度統計,就有相關頁面訪問統計,以及用戶的畫像等等。可是做爲開發人員來講,若是在本身作的系統中,按照本身的需求定製化數據埋點是否是很cool。web

一、頁面訪問量相關統計redis

頁面訪問量一般分爲:PV和UV。sql

(1)PV:頁面訪問人次。

(2)UV:頁面訪問人數。

頁面訪問量,並不是僅僅是內容吸引力決定的,影響因素有:入口,頁面位置,到主頁面深度等等。入口主要是UI視覺相關人員設計。入口位置能夠經過數據分析後進行調整,到主頁面深度能夠分析用戶的訪問路徑進行調整。

採集頁面加載 from、to 以獲知用戶訪問路徑:

image

分析能夠知道用戶廣泛訪問深度,每一層和每個頁面的流失率能夠很直觀看出來,從而調整核心頁面入口源和深度。

還有一些特殊狀況出現:好比PV穩定的頁面訪問量忽然暴跌,多是加載失敗或者報錯。

3、數據埋點方案實際操做

接下來我經過本身的系統接入數據埋點:https://chat.chengxinsong.cn

技術架構:vue+vuex+koa2+mysql+websocketIO+redis等。

一、方案一:全局定義Router.beforeEach方法

在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。

二、方案二:全局註冊混入beforeRouteEnter和beforeRouteLeave

雖然官方說,慎用全局混入對象。

放一下示例代碼

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。

4、全局PV統計方案總結

根據實際需求和評估使用不一樣的方案:

(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、開源做品:

相關文章
相關標籤/搜索