Appearance
谁是依赖?
这就引出了 Watcher 类,它算是每个数据的依赖,每个数据可能存在很多依赖,所以我们才会把这些依赖放到一个 Dep 类的数组里;
数组中的每一个元素都是一个 watch 实例,只要更新这个数组里的 watch 实例就行了,其实 watch 实例中有个回调函数,就是更新视图的函数
在编译阶段会对不同的数据进行newWatcher(vm,expOrFn,cb)
;在 wtcher 类中会进行以下操作
- 我们把 wacher 实例放到 Dep 的静态属性 target 上
- 然后调用数据的 getter ,把依赖(也就是Wathcer实例)添加到 Dep 实例的数组中去
- 当设置数据时,会触发
new Watcher()
传入的回调函数cb
下面来看代码:
- 地址:
src/core/observer/watcher.js
js
/**
* 使一个对象转化成可观测对象
* @param { Component } vm vue实例
* @param { string | Function } expOrFn 表达式,要watch 的属性名称
* @param { Function } cb 更新视图的回调函数
*/
class Watcher {
constructor(vm,expOrFn,cb){
this.vm=vm //vue实例
this.getter = expOrFn //要观察的表达式
this.cb=cb //回调函数
// expOrFn可以是字符串或者函数
// 什么时候会是字符串,例如我们正常使用的时候,watch: { x: fn }, Vue内部会将 `x` 这个key 转化为字符串
// 什么时候会是函数,其实 Vue 初始化时,就是传入的渲染函数 new Watcher(vm, updateComponent, ...);
if (typeof expOrFn === 'function') {
this.getter = expOrFn
} else {
this.getter = parsePath(expOrFn)
}
this.value=this.get()
}
get (){
let value
const vm = this.vm
// 我们把wacher实例放到Dep静态属性的target上
//vue源码中将其封装成了一个方法pushTarget,在src/core/observer/dep.js
Dep.target = this
value = this.getter.call(vm, vm) //触发getter添加依赖
Dep.target=null //释放
return value
}
update(){
// 触发回调,更新视图
this.cb.call(this.vm, value, oldValue)
}
}
接下来,我们对于整体流程进行一个梳理。