核心属性方法:
Object.defineProperty: 监听绑定对象;Dep: 收集依赖,通知更新;Watch: 订阅更新,通知视图更新;
组件思路:数据获取时收集依赖,数据更新变化时通知更新;
defineProperty:
function defineReactive (obj,key,val) {
if (arguments.length === 2) {
val = obj[key]
}
if(typeof val === 'object'){
new Observer(val)
}
const dep = new Dep() //实例化一个依赖管理器,生成一个依赖管理数组dep
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get(){
dep.depend() // 在getter中收集依赖
return val;
},
set(newVal){
if(val === newVal){
return
}
val = newVal;
dep.notify() // 在setter中通知依赖更新
}
})
}
Dep:
export default class Dep {
constructor () {
this.subs = []
}
addSub (sub) {
this.subs.push(sub)
}
// 删除一个依赖
removeSub (sub) {
remove(this.subs, sub)
}
// 添加一个依赖
depend () {
if (window.target) {
this.addSub(window.target)
}
}
// 通知所有依赖更新
notify () {
const subs = this.subs.slice()
for (let i = 0, l = subs.length; i < l; i++) {
subs[i].update()
}
}
}
Watch:
export default class Watcher {
constructor (vm,expOrFn,cb) {
this.vm = vm;
this.cb = cb;
this.getter = parsePath(expOrFn)
this.value = this.get()
}
get () {
window.target = this;
const vm = this.vm
let value = this.getter.call(vm, vm)
window.target = undefined;
return value
}
update () {
const oldValue = this.value
this.value = this.get()
this.cb.call(this.vm, this.value, oldValue)
}
}
大致流程:
Data通过observer转换成了getter/setter的形式来追踪变化。- 当外界通过
Watcher读取数据时,会触发getter从而将Watcher添加到依赖中。 - 当数据发生了变化时,会触发
setter,从而向Dep中的依赖(即Watcher)发送通知。 Watcher接收到通知后,会向外界发送通知,变化通知到外界后可能会触发视图更新,也有可能触发用户的某个回调函数等。
不足之处:仅只能观测到object数据的取值及设置值;
-
数据里
添加一对新的key/value,无法追踪到;---
Vue.set( target, propertyName/index, value )解决; -
数据里
删除一对新的key/value,无法追踪到;---
vue.delete(target, propertyName/index)解决;