起因:眾所周知黍氮,微信小程序的數(shù)據(jù)監(jiān)聽器observers只能在自定義組件中使用乐横,如果想要在頁面中實現(xiàn)類似的功能据悔,就只有通過其他的方法蝇完。其一就是通過模擬vue的watch來監(jiān)聽數(shù)據(jù)變化浆西。
實現(xiàn)如下:
1.新建一個watch.js文件存放監(jiān)聽器的邏輯函數(shù)畸悬,代碼如下:
/**
* 設(shè)置監(jiān)聽器
*/
export function 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];
let watchFun = watch[v].handler || watch[v]; // 兼容帶handler和不帶handler的兩種寫法
let deep = watch[v].deep; // 若未設(shè)置deep,則為undefine
observe(nowData, lastKey, watchFun, deep, page); // 監(jiān)聽nowData對象的lastKey
})
}
/**
* 監(jiān)聽屬性 并執(zhí)行監(jiān)聽函數(shù)
*/
function 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
observe(val, childKey, watchFun, deep, page); // 遞歸調(diào)用監(jiān)聽函數(shù)
})
}
Object.defineProperty(obj, key, {
configurable: true,
enumerable: true,
set: function(newVal) {
watchFun.call(page, newVal, val);
val = newVal;
if (deep) { // 若是深度監(jiān)聽,重新監(jiān)聽該對象绷蹲,以便監(jiān)聽其屬性。
observe(obj, key, watchFun, deep, page);
}
},
get: function() {
return val;
}
})
}
module.exports = {
setWatcher: setWatcher
}
2.在頁面中使用:假如有個同級頁面login.js顾孽,在該文件中引入watch.js祝钢,用法如下:
tips:如果有多個頁面都需要使用watch監(jiān)聽,可以直接在app.js中引入該文件若厚,注冊成全局函數(shù)拦英,這樣就不用每個文件都去引入watch.js了,只需要在使用的頁面onLoad的時候調(diào)用一次該函數(shù)测秸,就能愉快的使用watch了疤估。
// 在需要使用的頁面引入
import { setWatcher } from './watch.js';
Page({
data: {
str: '',
obj: {},
person: {'name':'張三'},
},
onLoad() {
// 在onload的時候調(diào)用一次監(jiān)聽函數(shù),然后就可以像vue一樣愉快的使用watch了
setWatcher(this);
}
// 用法完全和vue一樣霎冯,也能實現(xiàn)對象的深度監(jiān)聽
watch: {
//監(jiān)控簡單數(shù)據(jù)
str(val) {
console.log(val)
},
//監(jiān)控對象
obj: {
handler(val) {
console.log(val)
},
deep: true
}
//監(jiān)控對象的某個屬性
'person.name':{
handler(newVal,oldVal) {
console.log(newVal,oldVal)
},
deep: true
}
}
})