前文中我们在修改 data 属性后,手动调用了 _update
更新视图,这是不方便的,所以需要实现监听 data 的变化,自动触发页面的更新:
<div id="app" style="color:red;background:yellow">
{{name}} {{age}} {{name}} {{name}} {{name}}
</div>
所以我们想到给模板中的属性(e.g. {{name}}
、 {{age}}
…),都添加一个对应的收集器(dep
)
然后页面渲染的时候,将渲染逻辑封装到 watcher
中(vm._update(vm._render()
))
让 dep
记住这些 watcher
即可, 等到属性变化了可以找到对应的 dep
中存放的 watcher
进行重新渲染
如下图所示,每个组件都会有自己的 watcher
,当只有 num
变化,而 name
和 age
没有变化时,其实只用更新 侧边栏
一个组件,所以为了做区分,需要给每个 watcher
分配一个唯一 id
。
这也侧面说明了 Vue 组件化除了 复用
、 方便维护
外的另一个好处:局部渲染更新
dep
和 watcher
的关系是 多对多关系
:
src/observe/watch.js
Watcher
接收三个参数:
vm
watcher
属于哪个实例fn
vm
对应的渲染函数options
watcher
是不是一个渲染 watcher
let id = 0;
class Watcher { // 不同组件有不同的 watcher 目前只有一个 渲染根实例的
constructor(vm, fn, options) {
this.id = id++;
this.renderWatcher = options; // options = true 表明 watcher 是一个渲染 watcher
this.getter = fn; // getter 意味着调用这个函数可以发生取值操作
this.get(); // 默认先去取值一次
}
get() {
this.getter(); // 会去 vm 上取值 vm._update(vm._render) 取name 和age
}
}
// 需要给每个属性增加一个dep, 目的就是收集watcher
// 一个组件(视图)中 有多个属性 (n个属性会对应一个组件(视图)) n个dep对应一个watcher
// 1个属性 对应着多个组件(视图) 1个dep对应多个watcher
// 多对多的关系
export default Watcher;
在 lifecycle.js
中调用 watcher
更新视图