微信小程序官方沒有提供 watch,用來監聽 data 中的屬性的變化小程序
平常開發中若是少了 watch,會顯得束手束腳微信小程序
ES5 提供了 Object.defineProperty() 的方法,經過 getter/setter 劫持對象,實如今賦值時調用 setter 方法,執行 watch 中對應的方法,從而實現監聽。數組
setWatcher 函數遍歷會遍歷 data 中的全部屬性,給沒有一個屬性添加一個監聽器 observe微信
const setWatcher = (page) => { const data = page.data const watch = page.watch Object.keys(watch).forEach(key => { let targetData = data const targetKey = key const watchFun = watch[key].handler || watch[key] const deep = watch[key].deep observe(targetData, targetKey, watchFun, deep, page) }) }
observe 函數接收 5 個參數函數
若是 deep 爲 true 須要深度監聽,遞歸調用 observe,實現深度監聽this
使用 Object.defineProperty 的 setter 方法攔截外部對 data 數據的處理,同時調用 watchFn 實現監聽。code
watchFn 接收兩個參數,value 和 oldValue,使用 call 將 page 傳遞進去。使 watch 中能夠正常使用 page(this)對象
/** * * @param {Object} obj // data * @param {String} key // data 屬性 * @param {Fucntion} watchFun // 監聽函數 * @param {Boolean} deep // 是否深度監聽 * @param {Object} page // page */ const observe = (obj, key, watchFn, deep, page) => { let oldVal = obj[key] if (oldVal !== null && typeof oldVal === 'object' && deep) { Object.keys(oldVal).forEach(item => { observe(oldVal, item, watchFun, deep, page) }) } Object.defineProperty(obj, key, { configurable: true, enumerable: true, set(value) { if (value === oldVal) return watchFn.call(page, value, oldVal) oldVal = value }, get() { return oldVal } }) }
注意事項:遞歸
const observe = (obj, key, watchFun, deep, page) => { let oldVal = obj[key] if (oldVal !== null && typeof oldVal === 'object' && deep) { Object.keys(oldVal).forEach(item => { observe(oldVal, item, watchFun, deep, page) }) } Object.defineProperty(obj, key, { configurable: true, enumerable: true, set(value: any) { if (value === oldVal) return watchFun.call(page, value, oldVal) oldVal = value }, get() { return oldVal } }) } export const setWatcher = (page) => { const data = page.data const watch = page.watch Object.keys(watch).forEach(key => { let targetData = data const targetKey = key const watchFun = watch[key].handler || watch[key] const deep = watch[key].deep observe(targetData, targetKey, watchFun, deep, page) }) }
import { setWatcher} from "/utils/watch.js" Page({ data: { age: 12, person: { name: 'uccs' } }, onLoad() { setWatcher(this) }, watch: { age(val) { console.log(val) }, person: { deep: true, handler(val) { console.log(val) } } }, onClick() { this.data.age = 18 this.data.person.name = 'tiantian' } })