參考文檔:https://blog.csdn.net/xuyangxinlei/article/details/81408200
? 監(jiān)聽器的原理,將data中需監(jiān)聽的屬性寫在watch對象中,并給其提供一個方法凌简,當(dāng)被監(jiān)聽屬性的值改變時惕鼓,調(diào)用該方法蓬衡。所以很顯然唇礁,我們需要用到Javascript中的Object.defineProperty()方法碎捺,來手動劫持對象的getter/setter路鹰,從而實現(xiàn)給對象賦值時(調(diào)用setter)贷洲,執(zhí)行watch對象中相對應(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ù)組的元素彪腔,除了最后一個!
nowData = nowData[key[i]]; // 將nowData指向它的key屬性對象
}
let lastKey = key[key.length - 1];
// 假設(shè)key==='my.name',此時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對象的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對象下的每一個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對象調(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)聽該對象德挣,以便監(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改變時格嗅,調(diào)用該方法輸出新值。
}
}
})