在小程序中实现 watch
发表时间:2021-1-11
发布人:葵宇科技
浏览次数:47
微信小程序官方没有提供 watch,用来监听 data 中的属性的变化
日常开发中如果少了 watch,会显得束手束脚
ES5 提供了 Object.defineProperty() 的方法,通过 getter/setter 劫持对象,实现在赋值时调用 setter 方法,执行 watch 中对应的方法,从而实现监听。
设置监听者
setWatcher 函数遍历会遍历 data 中的所有属性,给没有一个属性添加一个监听器 observe
const setWatcher = (page) => {
const data = http://www.wxapp-union.com/page.data
const watch = page.watch
Object.keys(watch).forEach(key => {
let targetData = http://www.wxapp-union.com/data
const targetKey = key
const watchFun = watch[key].handler || watch[key]
const deep = watch[key].deep
observe(targetData, targetKey, watchFun, deep, page)
})
}
复制代码
实现监听器
observe 函数接收 5 个参数
- paga 中的 data
- data 中的属性 key
- watch 中的函数
- 是否要对 data 中的属性进行深度监听
- page,会被传递到监听函数中
如果 deep 为 true 需要深度监听,递归调用 observe,实现深度监听
使用 Object.defineProperty 的 setter 方法拦截外部对 data 数据的处理,同时调用 watchFn 实现监听。
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 =http://www.wxapp-union.com/== oldVal) return
watchFn.call(page, value, oldVal)
oldVal = value
},
get() {
return oldVal
}
})
}
复制代码
注意事项:
- watch 只能监听已存在的属性,数组的 pop() 和 push() 等方法不会触发
- 一开始不在 data 中的属性,后续动态添加的属性也不会触发
完整代码
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 =http://www.wxapp-union.com/== oldVal) return
watchFun.call(page, value, oldVal)
oldVal = value
},
get() {
return oldVal
}
})
}
export const setWatcher = (page) => {
const data = http://www.wxapp-union.com/page.data
const watch = page.watch
Object.keys(watch).forEach(key => {
let targetData = http://www.wxapp-union.com/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'
}
})
复制代码