这是我参与11月更文挑战的第24天,活动详情查看:2021最后一次更文挑战
在Vue
初次渲染过程中有一个比较关键的概念:渲染Watcher
,其主要是负责视图的更新,是之后响应式中data
和视图之间的核心枢纽
在Vue
中存在三种Watcher
,分别是Render Watcher
(渲染Watcher
)、Computed Watcher
(Computed
)和User Watcher
部分接触Vue
不久的小伙伴可能会比较惊讶为何会将Computed
和Render Watcher
、user Watcher
放在一起讨论,因为他们三者在Vue
的底层中都是基于Watcher
实现的,会通过传递不同的参数来进行区分
首先回顾前文处理初次渲染mountComponent
函数做的事情
export function mountComponent(vm, el) {
const options = vm.$options;
vm.$el = el;
vm._update(vm._render());
}
复制代码
在Vue
中每个组件都会创建一个对应的渲染Watcher
,当数据变化时视图需要及时响应,将最新的数据渲染至页面上,即响应式
需要对上述代码进行改造
export function mountComponent(vm, el) {
const options = vm.$options;
vm.$el = el; // 真实的DOM元素
/**
* Watcher 就是用来渲染的
* vm._render 通过解析的render方法 渲染出虚拟dom
* vm._update 通过虚拟dom 创建 真实dom
*/
// 无论渲染还是更新 都会执行
let updateComponent = () => {
// vm._render() 返回的是虚拟DOM
vm._update(vm._render());
};
// 渲染 watcher, 每一个组件都有一个watcher
// true 表示他是一个渲染watcher
new Watcher(vm, updateComponent, () => {}, true);
}
复制代码
需要注意:
- 为何要将
el
挂载到vm.$el
中,在日常开发中,我们将Vue
实例打印出来会发现都有这么一个属性,它的作用是用来记录真实的DOM节点,用于后续存放根据虚拟DOM创建的真实DOM updateComponent
函数在首次出创建渲染Watcher
是会调用一次,即初次渲染时。若是当data
改变时会触发试图的更新,也需要调用此函数进行处理- 需要注意
new Watcher
时传递的4个参数,不同的参数可用于区分三种Watcher
mountComponent
函数中_render
已经实现,_update
和Watcher
暂未实现,接下来先将Watcher
初始化,在此只需要掌握大致的流程和函数的作用即可,具体实现后文再实现
class Watcher {
constructor(vm, exprOrFn, callback, options) {
this.vm = vm;
this.callback = callback;
this.options = options;
this.getter = exprOrFn;
}
// 存储Watcher
get() {}
// 批量更新
update() {}
// 执行存储操作
run() {}
// 添加被观察者
addDep() {}
}
复制代码
_update
实现,次函数作为入口函数的存在,其中并不会做太多的事情,具体通过虚拟DOM创建真实DOM的流程全封装至patch
函数中,热门的diff
比较就在其中
Vue.prototype._update = function (vnode) {
const vm = this;
// 通过虚拟节点 渲染出来真实dom
// 需要用虚拟节点创建出来真实节点 替换掉 真实的 $el
vm.$el = patch(vm.$el, vnode);
};
复制代码