import Vue from 'vue'
import App from './App.vue
var app = new Vue({
el: 'app',
render(h) {
return h(App)
}
})
我们这里的tag是一个组件对象,所以vnode
是通过createComponent
()生成,方法的定义是在/vdom/createComponent.js/
文件中定义的
Ctor
可以是一个组件类型的类,或者是函数或对象,data
是vnode
相关的data
,context
是当前的vm
实例,children
是组件子vnode
等等
首先baseCtor取得是vm上$options._base
这个options._base我们在全局初始化的时候就赋值为Vue
在init的时候有一个合并options的操作,所以他会把Vue.options
合并到vm.$options
,所以我们这里通过context.options._base就访问到了vm.$options._base,所以这里baseCtor就是Vue
后面判断传入的Ctor是一个对象的话就会调用Vue.extend()去把这个对象转换成新的构造器
Vue.extend传入一个对象,返回一个构造函数,里面Super
指向自己Vue
,拿到superId
,cachedCtors
实际上是一个缓存的优化,然后拿到组件name extendOptions.name
,会在开发环境对这个组件name做一层校验
如果不满足就会报警告Invalid component name:XXX. Component names should conform to valid custom element...
。如果传入的组件name是一个内置的html标签有冲突的情况下会报警告Do not use built-in or reserved HTML elements as component
回到extend方法,接下来定义了一个子构造函数,也是调用了this._init()方法。把子构造函数原型指向父构造的原型,然后把子构造函数原型的构造指向自身。Sub.options
把父构造的options
和自身做了一个合并,接下来对自身的props和computed做了初始化。后面就是给Sub赋值一些属性和方法,目的就是为了和vue有一样的能力
最后赋值给cachedCtors[SuperId]
缓存起来,
多个组件引用一个组件的时候,构造器逻辑创建只会执行一次,下次走进来的时候发现,传入的是同一个对象,已经定义过并且有值了,SuperId是一样的话说明他们是基于同一个父构造器继承而来的,直接把缓存的构造器返回就行了,不用再创建
回到createComponent方法,接下来判断Ctor不是一个函数的话就会报警告Invalid Component definition...
接下来是一个异步组件的处理,现在先跳过
然后对data做处理并重新计算options
,因为可能会被全局的mixins
影响,对v-mode
l的一些判断,对props的一些处理以及对函数组件的一些处理
接下来是对自定义事件的一些处理。以上可以跳过
installComponentHooks(data)
安装一些组件的钩子,之前在patch过程中讲过,在不同的patch会执行不同的钩子create insert destory...
等等
installComponentHooks
里面遍历了hooksToMerge
,实际上是遍历拿到componentVNodeHooks
里面四个钩子函数合并到hooks
最后生成一个vnode
返回,这个vnode和我们之前的不一样,有一个前缀标识vue-component-...
.当我们调试看见vnode有一个这样的标识,就知道是一个组件。
比较核心的几点:
1.Ctor构造器的生成是继承Vue的
2.组件vnode的data都会有一些hook,这些hook会merge到自身组件的hooks上
3.生成组件vnode和之前的不一样,没有children(以后插槽会用到)多了一些标识和options