new Vue() & 组件(一)

177 阅读2分钟

单文件组件生成 VNode 过程

本节主要简述单文件组件生成组件 VNode 的过程,下节将简述组件 vnode 生成真实 DOM 节点的过程,部分代码就暂时不上图了!


image.png

对于单文件组件 *.vue 文件,是通过 import 导入,经过 vue-loader 编译生成组件的信息对象,该对象包含 render() 函数,以及处理生命周期 hookArray 类型,方便后续声明周期的合并。通过 import 导入的 app.vue 组件,组件信息对象 App 如下图所示:

初始化的历程与 new Vue()初始化 new Vue() & JSX(一) 初始化基本一致,所以就不过多介绍,下面只从不同的地方开始介绍。


首先 render() 函数生成组件 vnode 的过程有较大的的区别,接下来重点介绍一下。

因为是开发者手写 render() 函数,所以执行 vm._$createElemen(a,b,c,d) 函数,此时的参数 a 就是组件信息对象,再调用函数 createElement(vm,a,b,c,d,true) 进行参数处理后 d=2 然后调用 _createElement(vm,a,b,c,d) 函数。

_createElement(vm,tag) 函数内首先对参数进行校验(此处与上章节所走流程基本一致,所以省略),又对 tag 进行分类处理。此时的 tag 为编译后的组件信息 App,所以执行 vnode = createComponent(App) 然后返回组件 vnode .

createComponent(ctor:组件信息) 函数内主要有三个关键流程:构造子类(子组件)构造函数、安装组件的钩子函数、生成组件 vnode,具体如下:

1、构造子类(子组件)构造函数

  • 首先缓存 vm.$options._base 属性,即为 Vue 类构造函数。然后判断 ctor 若是对象类型,则通过 ctor = Vue.extend(ctor) 函数通过原型继承将一个对象转为一个继承于 Vue 类的构造函数 Sub 并返回该子类(VueComponent).
  • Vue.extend(ctor) 内,先定义子类 Sub = function VueComponent(){},然后通过 Sub.prototype = Object.create(Vue.prototype); Sub.prototype.constructor = Sub; 原型继承方式生成子类的原型对象,然后又对 Sub 本身扩展静态属性。
  • 首先合并属性 Sub.options = mergeOptions(Vue.options, ctor),然后 Sub['super'] = Super 指向父类的属性。然后又配置子类静态属性 Sub.cid,接着对配置中的属性 Sub.options.props/computed 进行了初始化。
  • 设置全局静态方法 Sub.extend/mixin/use/component/filter/directive() 通过 Vue 类进行赋值。以上扩展属性的目的就是让 Sub 拥有与 Vue 一样的能力。
  • 接着缓存父类的属性:Sub.superOptions = Super.options;
  • 缓存组件信息:Sub.extendOptions = ctor;
  • 缓存子构造函数的 optionsSub.sealedOptions = Sub.options;
  • 最后又缓存了子类构造函数 Sub() 在组件信息属性 ctor._Ctor 上,这样避免多次对同一组件重复构造,返回 return Sub.

2、安装组件钩子函数

  • 通过 installComponentHooks(data) 函数安装组件的钩子函数。整个过程就是遍历 componentVNodeHooks 对象的钩子函数合并到组件的 data.hook 属性上。
  • 钩子函数包括:init()、prepatch()、insert()、destroy()
  • 合并策略:若 data.hook[i] 不存在,则直接赋值 componentVNodeHooks[i] 函数。若 data.hook[i] 存在,则 data.hook[i] = func && func._merged=true 被赋值为函数 func,而 func 函数内依次 componentVNodeHooks[i]、data.hook[i] 执行两个组件钩子函数。

3、生成组件 vnode

  • 先设置组件名 tag = vue-component-{cid}-{name},然后再通过构造函数实例化组件 new VNode(tag, data, undefined..., context, componentOptions) 生成组件 vnode 对象,包含属性 componentOptions:{Ctor...} 其中 Ctor 为子组件构造器,组件的 vnode 是没有 children 属性的。

最后返回组件 vnode 对象并退出 createComponent() 函数。