写点什么

【Vue2.x 源码学习】第四十二篇 - 组件部分 - 组件挂载流程简述

用户头像
Brave
关注
发布于: 3 小时前

一,前言


上篇,组件部分-生成组件的真实节点;

本篇,组件部分-组件挂载流程分析;


二,组件挂载流程分析

1,示例

  • 全局组件:my-button,name:'全局组件';

  • 局部组件:my-button;name:'局部组件';

<body>  <div id="app">    <my-button></my-button>  </div>  <script src="./vue.js"></script>  <script>    // 全局组件    Vue.component('my-button',{      name:'my-button',      template:'<button>Hello Vue {{name}}</button>',      data(){        return { name: '全局组件'}      }    })    new Vue({      el: "#app",      components:{ // 局部组件        'my-button':{          template:'<button>Hello Vue {{name}}</button>',          data(){            return { name: '局部组件'}          }        }      }    });  </script>
复制代码

2,组件的挂载流程

// src/init.js
export function initMixin(Vue) { // 初始化 Vue.prototype._init = function (options) { const vm = this; vm.$options = mergeOptions(vm.constructor.options, options); initState(vm);
if (vm.$options.el) { vm.$mount(vm.$options.el) } }
Vue.prototype.$mount = function (el) { const vm = this; const opts = vm.$options; el = document.querySelector(el); vm.$el = el;
if (!opts.render) { let template = opts.template; if (!template) { template = el.outerHTML; } let render = compileToFunction(template); opts.render = render; }
mountComponent(vm); }
Vue.prototype.$nextTick = nextTick;}
复制代码


第一次进入,为根节点初始化,el 为 #app;


第二次进入,组件的初始化,el 为 undefined;


  • 继续,进行组件的挂载操作 mountComponent:

  • 组件的挂载:核心是创造出一个组件的虚拟节点,并调用他的更新方法 _update:

  • render.call 创造组件的虚拟节点 vnode,即 button 的虚拟节点:

  • vm.render 执行完成后,继续执行 _update 方法:

  • 这时,不能获取到上一次的虚拟节点:

  • 当组件挂载时,$patch 方法中的 el 为 null;

  • 此时,patch 内部判断了,如果 oldVnode 为 null,就使用组件的虚拟节点,创建出组件的真实节点:

  • 此时,返回的 vm.$el 就是 button 内部包含着内容:

  • 此时,子组件就挂载完毕了!

  • vnode.componentInstance 存在,说明是组件,createComponent 方法返回 true:

  • createElm 方法中,返回组件的 $el,即组件对应的真实节点 button:

  • createElm 递归处理,将生成的组件真实节点,放到对应的父节点上;

  • 再将完整的 div 挂在到页面上


三,完成流程


1,实现了 Vue.component,它的核心功能是注册成全局组件;

内部会自动调用 Vue.extend 方法,返回组件的构造函数;


2,在组件初始化时,会做组件的合并;

mergeOptions 先找自己的局部组件,然后再通过链继续向上找全局组件;


3,合并完成之后,内部会对模板进行编译操作,最终会走到_c('组件名')

做标签筛查,创建组件虚拟节点;若 Ctor 为对象,需要使用 Vue.extend 处理为组件的构造函数;

所以,所有的组件都是通过 Vue.extend 方法来实现的;


4,创建组件的真实节点

- 通过 new Ctor 得到组件实例;

- 组件实例调用 $mount 方法:生成组件的真实节点 $el,对应组件模板渲染后的结果

- 通过 vnode.componentInstance = new Ctor() 使后面可以拿到组件渲染后的结果: vnode.componentInstance.$el


5,将组件的 vnode.componentInstance.$el 插入到父标签中


6, 在 new Ctor() 组件实例化时,会执行组件初始化流程,为组件添加独立的渲染过程;

- 每个组件实例都拥有独立的渲染 watcher;

- 当组件渲染时,组件对应的属性会收集自己的渲染 watcher;

- 当组件更新时,只需更新组件对应的渲染 watcher 即可;

- 所以,组件是局部更新的,性能也会比较好


四,结尾


本篇,组件部分-组件挂载流程简述;

下篇,组件部分-组件相关流程总结;

用户头像

Brave

关注

还未添加个人签名 2018.12.13 加入

还未添加个人简介

评论

发布
暂无评论
【Vue2.x 源码学习】第四十二篇 - 组件部分 - 组件挂载流程简述