注入微信小程序,数据采集

in JavaScript with 0 comment

需求背景

以用户的维度来采集页面的UV,PV,等数据做统计

实现

思路就是对hook监听了,hook每触发一次,就to do something,目前微信小程序存在hook的,就是APP,Page,Component。总不能在每个存在生命周期的地方去加一段to do something的代码,其一影响业务,其二维护和开发难度过高。

那么我们考虑以依赖的方式注入,可以尝试在app.js输出App。Page和Component同理

console.log(App)
相关hook文档

  1. App
  2. Page
  3. Component

从以上说明构造出以下的代码

// collect.js
(() => {
    let _App = App;
    let _Page = Page;
    let _Component = Component;
    // 需监听的生命周期
    let appDefaultHookList = ['onLaunch', 'onShow', 'onHide', 'onError', 'onPageNotFound'];
    let pageDefaultHookList = ['onLoad', 'onShow', 'onReady', 'onHide', 'onUnload', 'onPullDownRefresh', 'onReachBottom', 'onShareAppMessage'];

    const collect = {

    }
})()

怎么注入?

call()知识

/*举个例子*/

// 改写
console.log(1); // 1
window.console.log = text => `${text}, add...`;
console.log(1); // "1, add..."

// 改写后追加
let _Number = Number;
Number = function(args){ console.log(args); return _Number.call(this, args) }
Number('1')
//这个时候会输出"1, add..."和返回Int 1

从以上原理得出以下代码

// collect.js
(() => {
    let _App = App;
    let _Page = Page;
    let _Component = Component;
    // 需监听的生命周期
    let appDefaultHookList = ['onLaunch', 'onShow', 'onHide', 'onError', 'onPageNotFound'];
    let pageDefaultHookList = ['onLoad', 'onShow', 'onReady', 'onHide', 'onUnload', 'onPullDownRefresh', 'onReachBottom', 'onShareAppMessage'];

    const collect = {
        hookTriggerHandle(instance, hook, scene){
            // 有些hook可能没有被注册所以得判断一下是否存在
            if(instance.hasOwnProperty(hook)){
                let pristine = instance[hook];
                instance[hook] = function(args){
                    collect.sendRubbish.call(this, args, hook, scene);
                    return pristine.call(this, args);
                }
            }else if(scene == 'PAGE'){
                    if(hook == pageDefaultHookList[1] || hook == pageDefaultHookList[3] || hook == pageDefaultHookList[4]){
                        instance[hook] = function(args){
                            collect.sendRubbish.call(this, args, hook, scene);
                        }
                    }
                }
            }
        },
    }

    // injection
    App = (me) => {
        appDefaultHookList.map(hookName => collect.hookTriggerHandle(me, hookName, 'APP'));
        _App(me);
    }

    Page = (me) => {
        pageDefaultHookList.map(hookName => collect.hookTriggerHandle(me, hookName, 'PAGE'));
        _Page(me);
    }

    Component = (me) => {
        //do something...
        _Component(me);
    }
})()

发送数据给服务端

// collect.js
(() => {
    let _App = App;
    let _Page = Page;
    let _Component = Component;
    // 需监听的生命周期
    let appDefaultHookList = ['onLaunch', 'onShow', 'onHide', 'onError', 'onPageNotFound'];
    let pageDefaultHookList = ['onLoad', 'onShow', 'onReady', 'onHide', 'onUnload', 'onPullDownRefresh', 'onReachBottom', 'onShareAppMessage'];

    const collect = {
        hookTriggerHandle(instance, hook, scene){
            // 有些hook可能没有被注册所以得判断一下是否存在
            if(instance.hasOwnProperty(hook)){
                let pristine = instance[hook];
                instance[hook] = function(args){
                    collect.sendRubbish.call(this, args, hook, scene);
                    return pristine.call(this, args);
                }
            }else if(scene == 'PAGE'){
                    if(hook == pageDefaultHookList[1] || hook == pageDefaultHookList[3] || hook == pageDefaultHookList[4]){
                        instance[hook] = function(args){
                            collect.sendRubbish.call(this, args, hook, scene);
                        }
                    }
                }
            }
        },

        sendRubbish(data, hook, scene){
            if(scene == 'APP'){
                // onLaunch
                if(hook == appDefaultHookList[0]){
                    // 场景值
                    collect.data.scene = data.scene;
                    collect.collectGarbage.call(this, {
                        args: null,
                        event: hook,
                        stayTime: null,
                        createUnix: +new Date(),
                        other: data.query,
                        isFirstOpen: true
                    });
                }
            }else if(scene == 'PAGE'){
                // special handle
                if(hook == pageDefaultHookList[1]){
                    // onShow
                    if(this.__route__ != collect.data.prevPageInfo.url){

                        // mark
                        collect.data.prevPageInfo = {
                            args: data || null,
                            event: hook,
                            stayTime: null,
                            createUnix: +new Date(),
                            other: this.options || null
                        }
                    }
                }
            }

            /* 
                push 发送给服务端
                collectGarbage 函数就不细写出来了,就是wx.request
            */
            collect.collectGarbage.call(this, {
                args: data || null,
                event: hook,
                stayTime: 0,
                createUnix: +new Date(),
                other: this.options || null
            });
        }
    }

    // injection
    App = (me) => {
        appDefaultHookList.map(hookName => collect.hookTriggerHandle(me, hookName, 'APP'));
        _App(me);
    }

    Page = (me) => {
        pageDefaultHookList.map(hookName => collect.hookTriggerHandle(me, hookName, 'PAGE'));
        _Page(me);
    }

    Component = (me) => {
        //do something...
        _Component(me);
    }
})()

总结

最后在app.js 引入 collect.js 即可实现效果,其实很可以做很多扩展,比如某个页面的函数执行触发之类的,如果哪里不对的,欢迎指出交流

Responses