Vue — mountComponent 挂载阶段

最后更新于:2022-04-02 08:12:47

>[success] # 挂载阶段 ~~~ 1.经过上个章节的分析$mount 有两个版本一个版本是'runtime only 版本的 Vue '对 在'src/platform/web/runtime/index.js',这个版本只能用render 函数,另一个版本 'runtime compiler'对应在'platforms\web\runtime-with-compiler.js' 边运行变将 '模板渲染'翻译成AST在转译成'render',即使是'runtime compiler'版本的$mount最后也都使用了 'runtime only 版本的 。 2.接下来Vue 要做的就是:函数被调用的时候就会渲染并且返回一个虚拟DOM的树。这个树非常轻量, 它的职责就是描述当前界面所应处的状态。当我们有了这个虚拟的树之后,再交给一个patch函数, 负责把这些虚拟DOM真正施加到真实的DOM上 3.接下来要做的就是生命周期这个部分 ~~~ ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/9e/ac/9eac1ac7684451cc3fd71623e6ca7ca4_929x446.png) >[info] ## 分析 挂载阶段 ~~~ 1.因此最后即使你使用的是'函数渲染'版本vue也是将render 变成 虚拟dom过程,整个 分析就变成了'runtime only' 版本 ~~~ >[danger] ##### runtime only 版本的 $mount ~~~ 1.'runtime only' 版本$mount 代码很短,最后整个工作交给了'mountComponent'(挂载组件) ~~~ ~~~ // wrap mount Vue.prototype.$mount = function ( el?: any, hydrating?: boolean ): Component { return mountComponent( this, el && query(el, this.$document), hydrating ) } ~~~ >[danger] ##### mountComponent(挂载组件) ~~~ 1.在下面的源码'mountComponent'函数的定义位于源码的'src/core/instance/lifecycle.js'中 2.下面代码做的事情: 2.1.判断实例上是否存在渲染函数,如果不存在,则设置一个默认的渲染函数createEmptyVNode,、 该渲染函数会创建一个注释类型的VNode节点 2.2.然后调用callHook函数来触发beforeMount生命周期钩子函数,beforeMount生命周期在这里触发。 这里就可以理解生命周期中说的,判断模板格式是否正确(2.1做了这个),也可以理解此时只是 render 函数并没有形成虚拟dom,也没有将页面内容真正渲染上 2.3.定义了'updateComponent',其中这个定义函数中参数'vm._render()'将会为我们得到一份最新的VNode 节点树,'如果调用了updateComponent函数,就会将最新的模板内容渲染到视图页面中' 2.4.接下来到了watcher 这部分,updateComponent函数作为第二个参数传给Watcher类从而创建了 watcher实例,那么updateComponent函数中读取的所有数据都将被watcher所监控 2.5挂载阶段才算是全部完成了,接下来调用挂载完成的生命周期钩子函数mounted ~~~ ~~~ export function mountComponent ( vm: Component, el: ?Element, hydrating?: boolean ): Component { vm.$el = el if (!vm.$options.render) { /*render函数不存在的时候创建一个空的VNode节点*/ vm.$options.render = createEmptyVNode if (process.env.NODE_ENV !== 'production') { /* istanbul ignore if */ if ((vm.$options.template && vm.$options.template.charAt(0) !== '#') || vm.$options.el || el) { warn( 'You are using the runtime-only build of Vue where the template ' + 'compiler is not available. Either pre-compile the templates into ' + 'render functions, or use the compiler-included build.', vm ) } else { warn( 'Failed to mount component: template or render function not defined.', vm ) } } } /*触发beforeMount钩子*/ callHook(vm, 'beforeMount') /*updateComponent作为Watcher对象的getter函数,用来依赖收集*/ let updateComponent /* istanbul ignore if 一些埋点操作 省略掉了*/ if (process.env.NODE_ENV !== 'production' && config.performance && mark) { ...... } else { updateComponent = () => { vm._update(vm._render(), hydrating) } } /*这里对该vm注册一个Watcher实例,Watcher的getter为updateComponent函数, 用于触发所有渲染所需要用到的数据的getter,进行依赖收集,该Watcher实例会存在所有 渲染所需数据的闭包Dep中*/ vm._watcher = new Watcher(vm, updateComponent, noop) hydrating = false // manually mounted instance, call mounted on self // mounted is called for render-created child components in its inserted hook if (vm.$vnode == null) { /*标志位,代表该组件已经挂载*/ vm._isMounted = true /*调用mounted钩子*/ callHook(vm, 'mounted') } return vm } ~~~
';