官方文档里面有 计算属性和 侦听属性,容易让人误解,其实一个是形容词加名词,一个是动宾结构,完全不一样。
关键点的要理解watch的机制,如果理解了的话,其实实现起来很简单,代码量很少。
增加实例方法
/**
* 观察某个属性
*
* 把属性的get方法拿出来,调用get的时候和会对应的新建的watch关联起来(注册了依赖关系)
* 属性修改的时候,就会调用所有的watch,然后就会调用回调。
* (这里的回调其实就是用户写的观察函数)
*
* @param {*} key
* @param {*} cb
*/
$watchField(key: string, cb: Function) {
const getter = Object.getOwnPropertyDescriptor(this, key).get
this.$watch(getter, cb)
}
/**
* 观察某个方法,调用这个方法之后,会执行callback
*
* @param {*} getter
* @param {*} cb
*/
$watch(getter: Function, cb: Function) {
new Watcher(this, {
getter,
cb
})
// fixme
//return function unwatchFn() {
// watcher.teardown()
//}
}
watch 类的简化代码
let uid = 0
export default class Watcher {
vm: Xiao
getter: Function
depIds: SimpleSet
cb: ?Function
value: ?any
_uid: number
/**
*
* @param {*} vm
* @param {*} option
* getter: 函数,为render函数或者属性的get函数
* cb : 回调函数,可以为空
*/
constructor(vm: Xiao, option: Object) {
this.vm = vm
this._uid = ++uid
this.getter = option.getter
this.cb = option.cb
this.depIds = new Set()
log(`[Watcher${this._uid}] _INIT_`)
this.get()
}
get() {
try {
pushTarget(this)
const value = this.getter.call(this.vm, this.vm)
// 监控属性的时候,回调不为空
if (this.cb) {
const oldValue = this.value
if (value !== oldValue) {
try {
this.cb.call(this.vm, value, oldValue)
} catch (error) {
}
}
}
// 保存最新值
this.value = value
}
finally {
popTarget()
}
}
/**
* Add a dependency to this directive.
*/
addDep(dep: Dep) {
if (!this.depIds.has(dep.id)) {
dep.addSub(this)
this.depIds.add(dep.id)
}
}
update() {
log(`[Watcher${this._uid}] update`)
// fixme
this.get();
}
}
测试代码
<!DOCTYPE html>
<html>
<head>
<title>Xiao框架之helloworld</title>
<script src="../dist/xiao.js"></script>
</head>
<body>
<h1>watch测试</h1>
<div id="demo">{{ fullName }}</div>
<script>
var app = new Xiao({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
watch: {
firstName: function (val, oldvalue) {
console.log('firstName', oldvalue, val);
this.fullName = val + ' ' + this.lastName
},
lastName: function (val, oldvalue) {
console.log('lastName', oldvalue, val);
this.fullName = this.firstName + ' ' + val
}
}
})
setTimeout(function(){
app.firstName = 'xx';
app.lastName = 'yy';
}, 2000);
</script>
</body>
</html>
官方文档里面有 计算属性和 侦听属性,容易让人误解,其实一个是形容词加名词,一个是动宾结构,完全不一样。
关键点的要理解watch的机制,如果理解了的话,其实实现起来很简单,代码量很少。
增加实例方法
watch 类的简化代码
测试代码