波多野吉不卡中文Av无码Av

      <strong id="fzzds"><track id="fzzds"></track></strong>
    1. <strong id="fzzds"></strong>
      <strong id="fzzds"></strong>
    2. <ruby id="fzzds"><bdo id="fzzds"><rp id="fzzds"></rp></bdo></ruby>
        <strike id="fzzds"></strike>
      1. 您現在的位置: 微信小程序 > 微信小程序運營 > 經驗 >

        小程序數據埋點實踐之曝光量

        來源:微信小程序 編輯:Yiyongtong.com 發布時間:2020-05-18 10:57熱度:

        什么是數據埋點

        所謂數據埋點就是應用在規定流程中 對特定行為或事件進行數據采集 。使用采集的數據做用戶分析和頁面分析,可以獲得應用的總體使用情況,為后續優化產品和運營提供數據支撐。常見數據埋點內容包括:訪問量、停留時長、曝光量、點擊量、跳出率等等。

        微信小程序也為我們提供了自定義分析統計,其中包括 API 上報(代碼埋點),填寫配置(無埋點,只需在公眾后臺配置)。而第三方統計平臺比較有名的就是阿拉丁統計,只需引入集成的 SDK,開發成本低,能夠滿足大部分的需求。

        數據埋點需要分析頁面流程,確定埋點需求,選擇埋點方式。如果是代碼埋點,主要關注觸發時機、條件判斷、捕獲數據,其次要注意是否有遺漏的場景沒有做到埋點。代碼埋點雖然成本較大(侵入代碼),但是精準度較高,能夠很好的滿足埋點需求。

        什么是曝光量

        曝光量顧名思義是 指定元素出現在可觀察視圖內的次數 ,也可以理解為展示量。

        通常我們會使用 點擊量 / 曝光量 得出 點擊率 ,作為衡量一個內容是否受用戶喜愛的指標之一。比如,曝光 100 次只有 10 人點擊,和曝光 100 次 有 100 個人點擊,很明顯后者更受用戶喜愛。利用這些數據參考,可以推薦更多用戶喜愛的內容,以此來留住用戶。

        交叉觀察者

        IntersectionObserver 接口,提供了一種異步觀察 目標元素與其祖先元素或頂級文檔視窗(viewport)交叉狀態 的方法,祖先元素與視窗(viewport)被稱為根(root)。簡單來說就是,觀察的目標是否和祖先元素和視窗發生交叉,即進入或離開。

        小程序從基礎庫 1.9.3 開始支持 wx.createIntersectionObserver 接口(組件內使用 this.createIntersectionObserver ),使用此接口可創建 IntersectionObserver對象 。對此接口不了解的可以查看 官方文檔 。

        基礎使用

        // 創建實例
        let ob = this.createIntersectionObserver()
        // 相對于文檔視窗監聽
        ob.relativeToViewport()
            .observe('.box', res => {
                // res.intersectionRatio 為相交比例
                if (res.intersectionRatio > 0) {
                    console.log('進入頁面')
                } else {
                    console.log('離開頁面')
                }
            })

        閾值

        在創建實例時可以傳入一些配置,其中 thresholds (閾值)是比較重要的一項配置,它可以控制觸發回調的時機。 thresholds 是一個數字類型的數組,默認為 [0] 。即相交比例為 0 時觸發一次回調,下面我們來設置閾值,看看會有什么改變:

        // 創建實例
        let ob = this.createIntersectionObserver({
            thresholds: [0, 0.5, 1]
        })

        從圖上可以看到,元素在相交比例為 0 、 0.5 、 1 都各自觸發了一次回調。在統計曝光量設置閾值非常有用,通常我會設置為 1 ,表示元素要完全展示在頁面上才會進行記錄,這樣數據會更加真實準確。

        收縮和擴展參照區域

        除了閾值之外還有另一項重要的設置,在使用 relativeTo 或 relativeToViewport 規定參照區域時,我們可以傳入配置 margins 來收縮和擴展參照區域。 margins 包括 left 、 right 、 top 、 bottom 四個參數配置。

        // 創建實例
        let ob = this.createIntersectionObserver()
        // 相對于文檔視窗監聽
        ob.relativeToViewport({
                bottom: -330
            })
            .observe('.box', res => {
                // res.intersectionRatio 為相交比例
                if (res.intersectionRatio > 0) {
                    console.log('進入頁面')
                } else {
                    console.log('離開頁面')
                }
            })

        上面將參照區域底部收縮 330px,可以理解為整體的區域從底部開始被裁剪 330px,因此元素只有進入頁面上半區才會觸發回調。

        進入正題

        經過以上一些介紹,相信大家對交叉觀察者的好處和使用都了解的差不多。接下來進入正題 ~

        背景

        此次我做的項目是資訊類目的小程序,主要用于發布和轉載一些學術文章。對于這種資訊的項目,需要通過數據埋點來收集用戶的閱讀習慣,以此來為用戶推薦文章。

        埋點方面用微信后臺提供的自定義分析以文章為單位進行收集,而我們自己后臺會以用戶為單位進行收集。前者得出整體用戶閱讀偏好和文章熱度,后者主要精確到用戶,分析用戶單位的閱讀偏好。

        改造組件

        在分析頁面布局和pm的商討后,多處需要統計曝光量的文章區域展示都大致相同,剛好也在封裝的列表組件里。于是將收集曝光量的邏輯都交由組件內部處理。

        組件改造:

        isObserver
        list
        

        以下部分代碼省略,只展示主要邏輯:

        <block wx:for="{{list}}" wx:key="id">
            <view class="artic-item artic-item-{{index}}" data-id="{{item.id}}" data-index="{{index}}">
            </view>
        </block>
        const app = getApp()
        Component({
            data: {
                currentLen: 0
            }
            properties: {
                list: {
                    type: Array,
                    value: []
                },
                isObserver: {
                    type: Boolean,
                    value: false
                }
            },
            observers: {
                list(list) {
                    if (this.data.isObserver === false) {
                        return
                    }
                    if (list.length) {
                        // currentLen 記錄當前列表的長度
                        // 用于計算監聽元素的索引,對已經監聽過的元素不再重復監聽
                        let currentLen = this.data.currentLen
                        for (let i = 0; i < list.length - currentLen; i++) {
                            let ob = this.createIntersectionObserver({
                                thresholds: [1]
                            })
                            ob.relativeToViewport()
                                .observe('.artic-item-' + (currentLen + i), res => {
                                    // 獲取元素的dataset
                                    let {
                                        id,
                                        index
                                    } = res.dataset
                                    if (res.intersectionRatio === 1) {
                                        // 此處收集曝光量,內部處理邏輯會在下面提及
                                        this.sendExsureId(id)
                                        // 元素出現后取消觀察者監聽,避免重復觸發
                                        ob.disconnect()
                                    }
                                })
                        }
                    }
                    this.data.currentLen = list.length
                }
            }
        })

        發現:bug:

        理想情況應該是切換到第二個分類打印3個文章,但由于組件開始記錄第一個分類列表的 currentLen ,在切換到第二個分類時, currentLen 沒有被清除,導致循環長度錯誤。

        解決:首先記錄列表第一項的 id ,當監聽列表變化,用新列表的第一項 id 作與之比較。若不相等,則表示列表被重新賦值,此時將 currentLen 置為0。

        Component({
            data: {
                flagId: 0,
                currentLen: 0
            }
            properties: {
                list: {
                    type: Array,
                    value: []
                },
                isObserver: {
                    type: Boolean,
                    value: false
                }
            },
            observers: {
                list(list) {
                    if (this.data.isObserver === false) {
                        return
                    }
                    if (list.length) {
                        // 比較id
                        if (this.data.flagId != list[0].id) {
                            this.data.currentLen = 0
                        }
                        let currentLen = this.data.currentLen
                        for (let i = 0; i < list.length - currentLen; i++) {
                            let ob = this.createIntersectionObserver({
                                thresholds: [1]
                            })
                            ob.relativeToViewport()
                                .observe('.artic-item-' + (currentLen + i), res => {
                                    let {
                                        id,
                                        index
                                    } = res.dataset
                                    if (res.intersectionRatio === 1) {
                                        this.sendExsureId(id)
                                        ob.disconnect()
                                    }
                                })
                        }
                    }
                    // 設置列表第一項id
                    this.data.flagId = list[0] ? list[0].id : 0
                    this.data.currentLen = list.length
                }
            }
        })

        組件優化

        因為需要提前監聽文章的相交狀態,在 list 傳入時就開始循環 observe ?,F在假設一個場景,在進入頁面時,已經為一些文章注冊完成回調,但用戶并沒有看過這些文章就退出頁面。那是不是表示這些實例都沒有被 disconnect 。

        解決:在 observe 時將每一個觀察者實例存入數組,當組件銷毀時檢查數組中是否有觀察者實例,如果有,則調用這些實例的 disconnect 。

        Component({
            data: {
                currentLen: 0,
                obItems: [] // 存放實例的數組
            },
            observers: {
                list(list) {
                    if (this.data.isObserver === false) {
                        return
                    }
                    if (list.length) {
                        if (this.data.flagId != list[0].id) {
                            this.data.currentLen = 0
                            // 取消實例的監聽
                            this.removeObItems()
                        }
                        let currentLen = this.data.currentLen
                        for (let i = 0; i < list.length - currentLen; i++) {
                            let ob = this.createIntersectionObserver({
                                thresholds: [1]
                            })
                            ob.relativeToViewport().observe('.artic-item-' + (currentLen + i), res => {
                                let {
                                    index,
                                    id
                                } = res.dataset
                                if (res.intersectionRatio === 1) {
                                    this.sendExsureId(id)
                                    ob.disconnect()
                                    // 取消監聽后 將實例移出數組
                                    this.data.obItems.shift()
                                }
                            })
                            // 將實例存入數組
                            this.data.obItems.push(ob)
                        }
                    } else {
                        // 取消實例的監聽
                        this.removeObItems()
                    }
                    this.data.flagId = list[0] ? list[0].id : 0
                    this.data.currentLen = list.length
                }
            },
            lifetimes: {
                detached() {
                    // 組件銷毀時 取消實例的監聽
                    this.removeObItems()
                }
            },
            methods: {
                removeObItems() {
                    if (this.data.obItems.length) {
                        this.data.obItems.forEach(ob => {
                            ob.disconnect()
                        })
                    }
                }
            }
        })

        收集處理

        現在組件能夠收集到曝光文章的ID,剩下的就是往后臺發送數據。那么問題來了,難道文章曝光一次就發起一次請求嗎?如果不怕和后端同事干架的話,你可以這么做。要知道多次發起請求,服務器:pear:會很大。用戶量比較大后,對服務器能夠承受的并發量會有很大的考驗。所以正確的做法應該是,把收集到的ID緩存起來,在達到一定數量的時候一起發送過去。

        接下來對收集的數據做些處理:

        // 這個上面收集曝光量的函數
        sendExsureId(id) {
            if (typeof app.globalData.exposureIds === 'undefined') {
                // exposureIds 是定義在全局用于存放曝光文章 ID 的數組
                app.globalData.exposureIds = []
            }
            app.globalData.exposureIds.push(id)
            // 當數組到達 50 個,開始上報數據
            if (app.globalData.exposureIds.length >= 50) {
                wx.$api.recordExposure({
                    // 因為 ID 比較多,我和后端約定好使用逗號分隔
                    ids: app.globalData.exposureIds.join(',')
                })
                // 上報后清空數組
                app.globalData.exposureIds = []
            }
        }

        看起來好像實現到這里就大功告成,但是我們還要考慮一種情況。假如用戶只看了 40 個就退出小程序,而上報條件是達到 50 個才會發送數據,那么這部分有用的數據就會被丟失。因為小程序沒有回調能夠監聽到小程序被銷毀,這里只能使用小程序的 onHide 函數來做些事情。當小程序進入后臺時 onHide 函數就會被執行,此時可以在函數里上報數據。

        App({
            onHide() {
                if (this.globalData.exposureIds.length) {
                    wx.$api.recordExposure({
                        ids: this.globalData.exposureIds.join(',')
                    })
                    this.globalData.exposureIds = []
                }
            }
        })

        寫在最后

        說實話,在埋點這方面的知識不算很熟悉,業務場景也比較簡單。因為沒有大佬指導,也是看著需求往這方面去做,有哪里錯誤或遺漏請指出。

        波多野吉不卡中文Av无码Av

          <strong id="fzzds"><track id="fzzds"></track></strong>
        1. <strong id="fzzds"></strong>
          <strong id="fzzds"></strong>
        2. <ruby id="fzzds"><bdo id="fzzds"><rp id="fzzds"></rp></bdo></ruby>
            <strike id="fzzds"></strike>