Vue 2.6源码学习(09)-组件初始化流程

125 阅读1分钟

我们在使用vue的时候,会拆分许多组件,一般按照路由拆分业务组件,还有我们自己封装的UI组件。 在vue中组件的使用比较多,简单介绍下vue组件化的初始流程。

1. 测试代码

 const vm = new Vue({
    el: '#app',
    components:{ // vm.$options.components['my'] = {my:模板}
        my:{
            template:'<div>my-component</div>'
        }
    }
});

2. 组件初始化流程

1.  注册组件的时候会将组件添加到$options.components中去,如vm.$options.components['my'] = {my:模板}
2.  创造组件的虚拟节点  createComponent    {tag:'my',data:{hook:{init}},componentOptions:{Ctor:Vue.extend( {my:模板})}}
3. - 创造真实节点的 createComponent  init -> new 组件().$mount()  -> vm.componentInstance 
4. - vm.$el 插入到父元素中

扩展 -同步组件的父子组件的生命周期

- 父组件 beforeCreate
- 父组件 created
- 父组件 beforeMount
      子组件beforeCreate
      子组件 created
      子组件 beforeMount
      子组件mounted
- 父组件 mounted

2.1. vue初始化

vm.mount(vm.mount(vm.options.el)挂载的时候判断是否有template,然后去编译。 编译的流程有三步: 解析,转换成ast,生成代码

image.png

image.png

image.png 模板编译生成的render函数,可以看到_c函数和with方法 image.png

2.2编译完成后, mount.call(this, el, hydrating) // 调用挂载

 // public mount method
  Vue.prototype.$mount = function (
    el,
    hydrating
  ) {
    el = el && inBrowser ? query(el) : undefined;

    // 做组件的挂载
    return mountComponent(this, el, hydrating)
  };

image.png

2.3_update方法内部调用patch方法去创建节点

vm.$el = vm.__patch__(prevVnode, vnode);
   patchVnode(oldVnode, vnode, insertedVnodeQueue, null, null, removeOnly);

// 组件的挂载 return mountComponent(this, el, hydrating)

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

2.4 createElm 内部判断是元素createElement,组件 createComponent 或者文本createTextNode,进行不同的操作

    child.$mount(hydrating ? vnode.elm : undefined, hydrating);
    

image.png

2.5组件加载完后componentInstance已经赋值,说明组件实例可复用,插入到父元素

image.png

  • 将父元素插入到body
  • 创建 vue-component-1-my
  • 创建h1 插入到component中
  • 创建text ,插入到h1中

小结

1.组件初始化整个流程比较长,在源码里面打断点记录了这些关键节点和方法调用。

2.为什么有些钩子的执行是先子后父亲,有些是先父后子 组件渲染是如何渲染的?

// 遇到父组件就先渲染父组件
<div id="app">
    // 遇到子组件就渲染子组件
    <my-button   >
    // 先渲染子组件后 完成才能渲染完毕父组件
</div>