自用。
使用Object.defineProperty()劫持数据的set操作,在监听对象改变后执行传入的Fn。
1. 定义watch.js
在根目录(miniprogram)下创建watch.js。
// watch.js
const observe = (obj, key, watchFn, deep, page) => {
let oldVal = obj[key]
// 如果监听对象是 object 类型并且指定deep => (深度监听)
if (oldVal !== null && typeof oldVal === 'object' && deep) {
// 递归子集,依次进行 observe
Object.keys(oldVal).forEach(item => {
observe(oldVal, item, watchFn, 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
}
})
}
export const setWatch = page => {
const data = page.data
const watch = page.watch
// 对每一个 watch 中的字段进行 observe
Object.keys(watch).forEach(key => {
let targetData = data
const targetKey = key
// 支持 deep 深度监听, 使用 deep 时需要配合 handler 使用
const watchFn = watch[key].handler || watch[key]
const deep = watch[key].deep
observe(targetData, targetKey, watchFn, deep, page)
})
}
2. 使用
在需要使用监听机制页面的js文件(如index.js)onLoad
钩子里,执行setWatch
(使用import
关键词从watch.js
引入),并传入当前页面实例this
,完成初始化。
// index.js
import { setWatch } from '../../watch.js'
Page({
data: {
foo: ''
},
watch: {
// 需要监听的字段
foo(newValue, oldValue) {
console.log('foo变化了,变化后的值是', val)
... // 具体操作
}
},
// watch初始化,传入当前页面实例this
onLoad() {
setWatch(this)
}
})