亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JS前端監控采集用戶行為的方法有哪些

發布時間:2022-07-22 11:42:08 來源:億速云 閱讀:110 作者:iii 欄目:開發技術

本篇內容介紹了“JS前端監控采集用戶行為的方法有哪些”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

    通用數據

    在一個產品中,用戶最基本的行為就是切換頁面。用戶使用了哪些功能,也能從切換頁面中體現出來。因此通用數據一般是在頁面切換時產生,表示某個用戶訪問了某個頁面。

    頁面切換對應到前端就是路由切換,可以通過監聽路由變化來拿到新頁面的數據。Vue 在全局路由守衛中監聽路由變化,任意路由切換都能執行這里的回調函數。

    // Vue3 路由寫法
    const router = createRouter({ ... })
    router.beforeEach(to => {
      // to 代表新頁面的路由對象
      recordBehaviors(to)
    })

    React 在組件的 useEffect 中實現相同的功能。不過要注意一點,監聽所有路由變化,則需要所有路由都經過這個組件,監聽才有效果。具體的方法是配置路由時加 * 配置:

    import HomePage from '@/pages/Home'
    <Route path="*" component={HomePage} />,

    然后在這個組件的的 useEffect 中監聽路由變化:

    // HomePage.jsx
    const { pathname } = useLocation();
    useEffect(() => {
      // 路由切換這個函數觸發
      recordBehaviors(pathname);
    }, [pathname]);

    上面代碼中,在路由切換時都調用了 recordBehaviors() 方法并傳入了參數。Vue 傳的是一個路由對象,React 傳的是路由地址,接下來就可以在這個函數內收集數據了。

    明確了在哪里收集數據,我們還要知道收集哪些數據。收集行為數據最基本的字段如下:

    app:應用的名稱/標識

    env:應用環境,一般是開發,測試,生產

    version:應用的版本號

    user_id:當前用戶 ID

    user_name:當前用戶名

    page_route:頁面路由

    page_title:頁面名稱

    start_at:進入時間

    end_at:離開時間

    上面的字段中,應用標識、環境、版本號統稱應用字段,用于標志數據的來源。其他字段主要分為 用戶頁面時間三類,通過這三類數據就可以簡單的判斷出一件事:誰到過哪個頁面,并停留了多長時間。

    應用字段的配置和獲取方式我們在上一節 搭建前端監控,如何采集異常數據? 中講過,就不做多余介紹了,獲取字段的方式都是通用的。

    下面介紹其他的幾類數據如何獲取。

    獲取用戶信息

    現代前端應用存儲用戶信息的方式基本都是一樣的,localStorage 存一份,狀態管理里存一份。因此獲取用戶信息從這兩處的任意一處獲得即可。這里簡單介紹下如何從狀態管理中獲取。

    最簡單的方法,在函數 recordBehaviors() 所處的 js 文件中,直接導入用戶狀態:

    // 從狀態管理里中導出用戶數據
    import { UserStore } from '@/stores';
    let { user_id, user_name } = UserStore;

    這里的 @/stores 指向我項目中的文件 src/stores/index.ts,表示狀態管理的入口文件,使用時替換成自己項目的實際位置。實際情況中還會有用戶數據為空的問題,這里需要單獨處理一下,方便我們在后續的數據查看中能看出分別:

    import { UserStore } from '@/stores';
    // 收集行為函數
    const recordBehaviors = ()=> {
      let report_date = {
        ...
      }
      if(UserStore) {
        let { user_id, user_name} = UserStore
        report_date.user_id = user_id || 0
        report_date.user_name = user_name || '未命名'
      } else {
        report_date.user_id = user_id || -1
        report_date.user_name = user_name || '未獲取'
      }
    }

    上面代碼中,首先判斷了狀態管理中是否有用戶數據,如果有則獲取,沒有則指定默認值。這里指定默認值的細節要注意,不是隨便指定的,比如 user_id 的默認值有如下意義:

    • user_id 為 0:表示有用戶數據,但沒有 user_id 字段或該字段為空

    • user_id 為 -1:表示沒有用戶數據,因而 user_id 字段獲取不到

    用戶數據是經常容易出錯的地方,因為涉及到登錄狀態和權限等復雜問題。指定了上述默認值后,就可以從收集到的行為數據中判斷出某個頁面用戶狀態是否正常。

    獲取頁面信息

    前面我們在監聽路由變化的地方調用了 recordBehaviors 函數并傳入了參數,頁面信息可以從參數中拿到,我們先看在 Vue 中怎么獲取:

    // 路由配置
    {
      path: '/test',
      meta: {
        title: '測試頁面'
      },
      component: () => import('@/views/test/Index.vue')
    }
    // 獲取配置
    const recordBehaviors = (to)=> {
      let page_route = to.path
      let page_title = to.meta.title
    }

    Vue 中比較簡單,可以直接從參數中拿到頁面數據。相比之下,React 的參數只是一個路由地址,想拿到頁面名稱還需要做單獨處理。

    一般在設計權限時,我們會在服務端會維護一套路由數據,包含路由地址和名稱。路由數據在登錄后獲取,存在狀態管理中,那么有了 pathname 就可以從路由數據中找到對應的路由名稱。

    // React 中
    import { RouteStore } from '@/stores';
    const recordBehaviors = (pathname) => {
      let { routers } = RouteStore; // 取出路由數據
      let route = routers.find((row) => (row.path = pathname));
      if (route) {
        let page_route = route.path;
        let page_title = route.title;
      }
    };

    這樣,頁面信息的 page_route、page_title 兩個字段也拿到了。

    設置時間

    行為數據中用兩個字段 start_atend_at 分別表示用戶進入頁面和離開頁面的時間。這兩個字段非常重要,我們在后續使用數據的時候可以判斷出很多信息,比如:

    • 某個用戶在某個頁面停留了多久?

    • 某個段時間內,某個用戶停留在哪幾個頁面?

    • 某個時間段內,哪個頁面的用戶停留時間最長?

    • 某個頁面,哪些用戶的使用率最高?

    還有很多信息,都能根據這兩個時間字段判斷。開始時間很好辦,函數觸發時直接獲取當前時間:

    var start_at = new Date();

    結束時間這里需要考慮的情況比較多。首先要確定數據什么時候上報?用戶進入頁面后上報,還是離開頁面時上報?

    如果進入頁面時上報,可以保證行為數據一定會被記錄,不會丟失,但此時 end_at 字段必然為空。這樣的話,就需要在離開頁面時再調接口,將這條記錄的 end_time 更新,這種方式的實現比較麻煩一些:

    // 進入頁面時調用
    const recordBehaviors = () => {
      let report_date = {...} // 此時 end_at 為空
      http.post('/behaviors/insert', report_date).then(res=> {
        let id = res.id // 數據 id
        localStorage.setItem('CURRENT_BEHAVIOR_ID', id)
      })
    }
    // 離開頁面時調用:
    const updateBehaviors = ()=> {
      let id = localStorage.getItem('CURRENT_BEHAVIOR_ID')
      let end_at = new Date()
      http.post('/behaviors/update/'+id, end_at) // 根據 id 更新結束時間
      localStorage.removeItem('CURRENT_BEHAVIOR_ID')
    }

    上面代碼中,進入頁面先上報數據,并保存下 id,離開頁面再根據 id 更新這條數據的結束時間。

    如果在離開頁面時上報,那么就要保證離開頁面前上報接口已經觸發,否則會導致數據丟失。在滿足這個前提條件下,上報邏輯會變成這樣:

    // 進入頁面時調用
    const recordBehaviors = () => {
      let report_date = {...} // 此時 end_at 為空
      localStorage.setItem('CURRENT_BEHAVIOR', JSON.stringify(report_date));
    }
    // 離開頁面時調用
    const reportBehaviors = () => {
      let end_at = new Date()
      let report_str = localStorage.getItem('CURRENT_BEHAVIOR')
      if(report_str) {
        let report_date = JSON.parse(report_str)
        report_date.end_at = end_at
        http.post('/behaviors/insert', report_date)
      } else {
        console.log('無行為數據')
      }
    }

    對比一下這兩種方案,第一種的弊端是接口需要調兩次,這會使接口請求量倍增。第二種方案只調用一次,但是需要特別注意可靠性處理,總體來說第二種方案更好些。

    特定數據

    除了通用數據,大部分情況我們還要在具體的頁面中收集某些特定的行為。比如某個關鍵的按鈕有沒有點擊,點了多少次;或者某個關鍵區域用戶有沒有看到,看到(曝光)了多少次等等。

    收集數據還有一個更專業的叫法 &mdash;&mdash;&mdash;&mdash; 埋點。直觀理解是,哪里需要上報數據,就埋一個上報函數進去。

    通用數據針對所有頁面自動收集,特定數據就需要根據每個頁面的實際需求手動添加。以一個按鈕為例:

    <button onClick={onClick}>點擊</button>;
    const onClick = (e) => {
      // console.log(e);
      repoerEvents(e);
    };

    上面代碼中,我們想記錄這個按鈕的點擊情況,所以做了一個簡單的埋點 &mdash;&mdash;&mdash;&mdash; 在按鈕點擊事件中調用 repoerEvents() 方法,這個方法內部會收集數據并上報。

    這是最原始的埋點方式,直接將上報方法放到事件函數中。repoerEvents() 方法接收一個事件對象參數,在參數中獲取需要上報的事件數據。

    特定數據與通用數據的許多字段是一樣的,收集特定數據需要的基本字段如下:

    app:應用的名稱/標識

    env:應用環境,一般是開發,測試,生產

    version:應用的版本號

    user_id:當前用戶 ID

    user_name:當前用戶名

    page_route:頁面路由

    page_title:頁面名稱

    created_at:觸發時間

    event_type:事件類型

    action_tag:行為標識

    action_label:行為描述

    這些基本字段中,前 7 個字段與前面通用數據的獲取完全一樣,這里就不贅述了。實際上特定數據需要獲取的專有字段只有 3 個:

    event_type:事件類型

    action_tag:行為標識

    action_label:行為描述

    這三個字段也非常容易獲取。event_type 表示事件觸發的類型,比如點擊、滾動、拖動等,可以在事件對象中拿到。action_tag 和 action_label 是必須指定的屬性,表示本次埋點的標識和文字描述,用于在后續的數據處理時方便查閱和統計。

    了解了采集特定數據是怎么回事,接下來我們用代碼實現。

    手動埋點上報

    假設要為登錄按鈕做埋點,按照上面的數據采集方式,我們書寫代碼如下:

    <button data-tag="user_login" data-label="用戶登錄" onClick={onClick}>
      登錄
    </button>;
    const onClick = (e) => {
      // console.log(e);
      repoerEvents(e);
    };

    代碼中,我們通過元素的自定義屬性傳遞了 tag 和 label 兩個標識,用于在上報函數中獲取。

    上報函數 repoerEvents() 代碼邏輯如下:

    // 埋點上報函數
    const repoerEvents = (e)=> {
      let report_date = {...}
      let { tag, label } = e.target.dataset
      if(!tag || !label) {
        return new Error('上報元素屬性缺失')
      }
      report_date.event_type = e.type
      report_date.action_tag = tag
      report_date.action_label = label
      // 上報數據
      http.post('/events/insert', report_date)
    }

    這樣就實現了一個基本的特定數據埋點上報功能。

    全局自動上報

    現在我們回過頭來梳理一下這個上報流程,雖然基本功能實現了,但是還有些不合理之處,比如:

    • 必須為元素指定事件處理函數

    • 必須為元素添加自定義屬性

    • 在原有事件處理函數中手動添加埋點,侵入性高

    首先我們的埋點方式是基于事件的,也就是說,不管元素本身是否需要事件處理,我們都要給他加上,并在函數內部調用 repoerEvents() 方法。如果一個項目需要埋點的地方非常多,這種方式的接入成本就會非常高。

    參考之前做異常監控的邏輯,我們換一個思路:能否全局監聽事件自動上報呢?

    思考一下,如果要做全局監聽事件,那么只能監聽需要埋點的元素的事件。那么如何判斷哪些元素需要埋點呢?

    上面我們為埋點的元素指定了 data-tag 和 data-label 兩個自定義屬性,那是不是根據這兩個自定義屬性判斷就可以?我們來試驗一下:

    window.addEventListener('click', (event) => {
      let { tag, label, trigger } = event.target.dataset;
      if (tag && label && trigger == 'click') {
        // 說明該元素需要埋點
        repoerEvents(event);
      }
    });

    上面代碼還多判斷了一個自定義屬性 dataset.trigger,表示元素在哪種事件觸發時需要上報。全局監聽事件需要這個標識,這樣可避免事件沖突。

    添加全局監聽后,收集某個元素的特定數據就簡單了,方法如下:

    <button data-tag="form_save" data-label="表單保存" data-trigger="click">
      保存
    </button>

    試驗證明,上述全局處理的方式是可行的,這樣的話就不需要在每一個元素上添加或修改事件處理函數了,只需要在元素中添加三個自定義屬性 data-tagdata-labeldata-trigger 就能自動實現數據埋點上報。

    組件上報

    上面全局監聽事件上報的方式已經比手動埋點高效了許多,現在我們再換一個場景。

    一般情況下當埋點功能成熟之后,會封裝成一個 SDK 供其他項目使用。如果我們將采集數據按照 SDK 的思路實現,讓開發者在全局監聽事件,是不是一個好的方式呢?

    顯然是不太友好的。如果是一個 SDK,那么最好的方式是將所有內容聚合成一個組件,在組件內實現上報的所有功能,而不是讓使用者在項目中添加監聽事件。

    封裝組件的話,那么組件的功能最好是將要添加埋點的元素包裹,這樣自定義元素也就不需要指定了,而轉為組件的屬性,然后在組件內實現事件監聽。

    以 React 為例,我們看一下如何將上面的采集功能封裝為組件:

    import { useEffect, useRef } from 'react';
    const CusReport = (props) => {
      const dom = useRef(null);
      const handelEvent = () => {
        console.log(props); // {tag:xx, label:xx, trigger:xx}
        repoerEvents(props);
      };
      useEffect(() => {
        if (dom.current instanceof HTMLElement) {
          dom.current.addEventListener(props.trigger, handelEvent);
        }
      }, []);
      return (
        <span ref={dom} className="custom-report">
          {props.children}
        </span>
      );
    };
    export default CusReport;

    組件使用方式如下:

    <CusReport tag="test" label="功能測試" trigger="click">
      <button>測試</button>
    </CusReport>

    這樣就比較優雅了,不需要修改目標元素,只要把組件包裹在目標元素之外即可。

    “JS前端監控采集用戶行為的方法有哪些”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    js
    AI

    余庆县| 德清县| 株洲市| 宁河县| 阿拉善右旗| 临夏县| 贺州市| 嵩明县| 舒兰市| 鲁甸县| 库伦旗| 乌兰县| 伊金霍洛旗| 改则县| 衡水市| 广德县| 清镇市| 大理市| 右玉县| 安泽县| 金坛市| 友谊县| 恩平市| 宜宾市| 湖南省| 乳山市| 永修县| 达拉特旗| 扎鲁特旗| 元阳县| 莱芜市| 额尔古纳市| 昭平县| 沁水县| 双流县| 古交市| 峡江县| 云浮市| 汉阴县| 寿光市| 西贡区|