组件mount挂载的过程,是将模板转为render函数,通过render生成虚拟dom,然后再转为真实dom过程
组件挂载时间节点
当通过new Vue初始化实例vm时,会执行_init方法。此时,如果传参中包含el|template|render,会执行$mount进行挂载
Vue.prototype._init = function(opts) {
...
if(vm.$options.el) {
vm.$mount(vm.$options.el)
}
}
$mount
在vue的原型上添加$mount,进行组件的挂载。在进行挂载时,如果用户没有传递render参数,需要将el|template先转为render函数;其次执行mountComponent方法
Vue.prototype.$mount = function(el) {
const vm = this;
const options = vm.$options;
el = document.querySelector(el);
if (!options.render) {
let template = options.template;
if(!template && el) {
template = el.outerHTML;
}
const render = compileToFunction(template);
options.render = render;
}
mountComponent(vm, el)
}
mountComponent组件更新函数
在组件更新函数中,先通过_render将render的模板编译结果转为虚拟dom,然后通过_update将虚拟dom转为真实dom。创建watcher实例,将组件更新函数作为参数传递;在watcher的constructor中执行组件更新函数,实现组件的挂载
function mountComponent(vm, el){
const options = vm.$options
vm.$el = el;
let updateComponent= () => {
vm._update(vm._render());
}
new Watcher(vm, updateComponent, () => {}, true);
}
watcher
class Watcher{
constructor(vm, exprOrFn, callback=()=> {}, options={}){
this.vm = vm
this.exprOrFn = exprOrFn
if (typeof exprOrFn === 'function') {
this.getter = exprOrFn
}
this.callback = callback
this.options = options
this.id = id++;
this.get(); // 创建watcher 默认会调用自身的get方法,执行Vue._update方法,将虚拟dom转为真实dom
}
get () {
this.getter();
}
}