微信小程序?qū)崿F(xiàn)watch屬性監(jiān)聽數(shù)據(jù)變化

參考文檔:https://blog.csdn.net/xuyangxinlei/article/details/81408200

? 監(jiān)聽器的原理,將data中需監(jiān)聽的屬性寫在watch對(duì)象中,并給其提供一個(gè)方法,當(dāng)被監(jiān)聽屬性的值改變時(shí),調(diào)用該方法。所以很顯然,我們需要用到Javascript中的Object.defineProperty()方法,來手動(dòng)劫持對(duì)象的getter/setter,從而實(shí)現(xiàn)給對(duì)象賦值時(shí)(調(diào)用setter),執(zhí)行watch對(duì)象中相對(duì)應(yīng)的函數(shù),達(dá)到監(jiān)聽效果。

? 首先,既然是微信小程序自定義watch屬性,我建議直接將代碼寫在app.js內(nèi),需要使用的頁面直接onLoad()內(nèi)調(diào)用getApp().setWatch(...)即可。

一、監(jiān)聽器代碼:

? 為了能夠全局使用監(jiān)聽器,我們需要在 app.js 中添加該方法(或者外部引入)

 /**
     * 設(shè)置監(jiān)聽器
     */
setWatcher(page) {
    let data = page.data;
    let watch = page.watch;
    Object.keys(watch).forEach(v => {
        let key = v.split('.'); // 將watch中的屬性以'.'切分成數(shù)組
        let nowData = data; // 將data賦值給nowData
        for (let i = 0; i < key.length - 1; i++) { // 遍歷key數(shù)組的元素,除了最后一個(gè)!
            nowData = nowData[key[i]]; // 將nowData指向它的key屬性對(duì)象
        }
        let lastKey = key[key.length - 1];
        // 假設(shè)key==='my.name',此時(shí)nowData===data['my']===data.my,lastKey==='name'
        let watchFun = watch[v].handler || watch[v]; // 兼容帶handler和不帶handler的兩種寫法
        let deep = watch[v].deep; // 若未設(shè)置deep,則為undefine
        this.observe(nowData, lastKey, watchFun, deep, page); // 監(jiān)聽nowData對(duì)象的lastKey
    })
},
/**
* 監(jiān)聽屬性 并執(zhí)行監(jiān)聽函數(shù)
*/
observe(obj, key, watchFun, deep, page) {
    var val = obj[key];
    // 判斷deep是true 且 val不能為空 且 typeof val==='object'(數(shù)組內(nèi)數(shù)值變化也需要深度監(jiān)聽)
    if (deep && val != null && typeof val === 'object') { 
        Object.keys(val).forEach(childKey=>{ // 遍歷val對(duì)象下的每一個(gè)key
            this.observe(val,childKey,watchFun,deep,page); // 遞歸調(diào)用監(jiān)聽函數(shù)
        })
    }
    var that = this;
    Object.defineProperty(obj, key, {
        configurable: true,
        enumerable: true,
        set: function(value) {
            // 用page對(duì)象調(diào)用,改變函數(shù)內(nèi)this指向,以便this.data訪問data內(nèi)的屬性值
            watchFun.call(page,value,val); // value是新值,val是舊值
            val = value;
            if(deep){ // 若是深度監(jiān)聽,重新監(jiān)聽該對(duì)象,以便監(jiān)聽其屬性。
                that.observe(obj, key, watchFun, deep, page); 
            }
        },
        get: function() {
            return val;
        }
    })
}
二、在需要監(jiān)聽的頁面引入使用監(jiān)聽器:
// 需要使用監(jiān)聽器的頁面
Page({
    data: {
        name:"xuyang"
    },
    onLoad(){
        getApp().setWatcher(this.data, this.watch); // 設(shè)置監(jiān)聽器
        this.setData({
            name:'lxm'
        })
    },
    watch:{
        name:function(newValue){
            console.log(newValue); // name改變時(shí),調(diào)用該方法輸出新值。
        }
    }
})
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容