Vue实例挂载的实现

498 阅读2分钟

当执行new Vue()时,会调用vue构造函数中的_init方法。

在 _init 方法中对vue进行一系列初始化之后,调用vm.mount(vm.mount(vm.options.el)进行vue实例的挂载。本篇,我们就来聊聊vue实例挂载的实现。

在入口文件 entry-runtime-with-compiler.js里找到了mount方法的定义,先将Vue原型上的mount方法的定义,先将Vue原型上的mount方法保存为mount,再重写Vue原型上的mount方法。这样做的目的是因为vue最终要将所有的el或者template转换成render函数,重写的mount方法。这样做的目的是因为vue最终要将所有的el或者template转换成render函数,重写的mount方法会经过一层转换,通过compileToFunctions方法将el或者template转换成render函数,最后再调用原始的$mount方法。

定义在Vue原型上的$mount方法里,通过query方法拿到el的dom对象,最后调用mountComponent方法,传递的参数为Vue实例自身,el的dom对象,以及false。

mountComponent方法在core/instance/lifecycle.js中声明。

mountComponent函数中主要干了两件事,一:声明了updateComponent函数,二:创建了一个Watcher对象,并将updateComponent函数作为了Watcher的构造参数。updateComponent函数并没有显示的执行,那么我们将目标放在Watcher上,在new Watcher()的时候vue做了哪些事情呢?Watcher里的lazy属性默认为false,在构造函数中将会调用this.get()方法,get方法里会调用this.getter,这里的getter就是我们传递进来的updateComponent函数,也就是说我们最终在mountComponent函数里调用了updateComonent方法。

updateComponent函数调用后会执行vm._render()与vm._update()

vm.render()方法最终返回的是一个vnode

vm._update方法里判断是否有旧的vnode,如果没有,则是第一次渲染,如果有则是更新渲染,第一次渲染以及更新渲染都执行__patch__方法,只是传递的参数不同。

在__patch__方法的实现中,如果oldVnode不存在,则会通过createElm方法创建dom对象并添加到文档中。

到这里,vue实例挂载的实现我们就分析完了。最后总结一下vue实例挂载的整个流程:Vue对象创建 -> 调用 _init函数初始化 -> 将模板或者el转换成render函数 -> 调用$mount方法进行挂载 -> 将要挂载到dom上的内容看视为一个组件component,执行mountComponent进行组件的挂载 -> 挂载组件的过程可视为一次组件更新的过程,执行组件更新方法updateComponent -> vue是将vnode渲染成dom,所以调用_render()方法获取我们需要更新的vnode -> 拿到vnode执行_update()开始更新 -> vue第一次渲染视图或者更新视图都是调用__patch__方法 -> 在 __patch__方法里将vnode转换成真实dom,并最终添加到页面中。-> 整个挂载过程结束。