vue源码解析组件挂载过程

1,734 阅读3分钟

本文会从源码角度分析页面中组件实例生成到最终挂载到页面中的过程

先说下本文会得出的结论:组件创建过程自上而下,组件挂载过程自下而上

这里从源码的实现流程整理了一下组件化机制的思维导图: www.processon.com/mindmap/5e3…

本文使用的代码如下,文章会分析comp组件是如何挂载到页面上的:

<body>
    <div id="demo">
        <h1>组件挂载源码解析</h1>
        <comp></comp>
    </div>
    <script>
        Vue.component('comp', {
            template: '<div>I am comp</div>'
        })
        // 创建实例并挂载
        const app = new Vue({}).$mount('#demo');
    </script>
</body>

1、创建一个全局组件

 Vue.component('comp', {
    template: '<div>I am comp</div>'
})

解析:

局部组件会继承全局组件里的组件,所以在根实例或其它组件内可以直接使用全局组件。

其基本原理如下:

  • 当我们页面中使用了一个组件,该组件的实例vm,该组件引用的外部组件(局部组件)都保存在vm.$options.components里面,当页面中使用组件的时候就会到vm.$options.components里找。
  • 全局组件都保存在Vue.options.components里面
  • vm.$options.components.__proto__指向Vue.options.components,所以每个每个组件内部都可以像使用局部组件一样使用全局组件,因为在使用组件时在vm.$options.components里找不到就会到Vue.options.components里找

2、创建根实例

const app = new Vue({})

这里会完成实例的数据初始化、响应式,以及调用beforeCreate和created生命周期函数

3、挂载根实例

const app = new Vue({}).$mount('#demo');

挂载根实例过程

  • 3.1:获取#demo里的模版编译成渲染函数_render
  • 3.2:执行渲染函数_render获取虚拟dom(vnode),然后执行_update方法,_update会根据虚拟dom生成真实dom,详细过程看3.3
vm._update(vm._render())
  • 3.3 在_update方法内部会调用createElm方法创建真实dom,创建真实dom是采用自上而下的方法,其原理图如下:

  • 创建过程
    • 首先调用createElm(vnode)开始创建
    • 在createElm方法内部会遍历子节点递归调用createElm,所以这里会调用createElm(comp1的vnode)
    • 在创建comp1的时候,也会先递归创建其孩子节点
    • 综合以上,可以得出vnode的创建顺序是:
      • 先创建div1
      • 再创建其孩子节点comp1
      • 再创建comp1的孩子节点div3和comp2
      • div3和comp2创建完成后挂载到comp1上
      • comp1挂载到div1上
      • comp1都处理完成了,开始创建div2
      • 然后创建div2的孩子节点div4和div5
      • div4和div5创建完成后挂载到div2
      • div2挂载到div1
      • div1整个挂载到页面对应的位置中

从上面的步骤即可以看出组件自上而下创建,自下而上挂载的流程就比较明显了,其实不止组件,页面中的所有元素都是自上而下创建,自下而上挂载的,当所有元素都挂载到div1后,再把整个dom插入到页面中,可以把组件当成一个特殊的元素,在遇到组件元素的时候会进行组件的实例化、数据响应等操作后再挂载

在自上而下创建dom的过程中,遇到组件的时候,其详细的处理步骤是:

以comp组件为例

Vue.component('comp', {
    template: '<div>I am comp</div>'
})
  • 1)从组件的配置选项中拿出template,这里为<div>I am comp</div>,将其转化为渲染函数
  • 2)用extend方法得到组件的构造函数,并调用得到组件实例
  • 3)得到组件实例后调用$mount方法进行挂载
  • 4)生成组件的更新函数和组件的Watcher
  • 5)组件的Watcher会调用组件更新函数
  • 6)组件更新函数会先调用组件的渲染函数得到组件的虚拟dom,然后再调用_update方法执行组件的更新
  • 7)_update方法里会调用createElm方法将虚拟dom生成真实dom,其过程会对虚拟dom的孩子节点进行递归遍历,采用自上而下创建,自下而上挂载的方法完成整个组件真实dom的创建 以上即为在创建真实dom的过程中,遇到孩子节点是组件时候的处理过程