1.说明
我们以Vue-cli 初始化的代码为例,来分析一下 Vue 组件初始化的一个过程。
import Vue from 'vue'
import App from './App.vue'
var app = new Vue({
el: '#app',
// 这里的 h 是 createElement 方法
render: h => h(App)
})
和我们上一章相同的点也是通过 render 函数去渲染的,不同的这次通过 createElement 传的参数是一个组件而不是一个原生的标签。
2.接上一章
上一章我们在分析虚拟DOM的实现
过程是 init –> $mount(挂载) –> render(参生虚拟DOM) –> path (映射真实DOM)
render(参生虚拟DOM) 是调用 createElement 的实现的时候,它最终会调用 _createElement 方法,其中有一段逻辑是对参数 tag 的判断,如果是一个普通的 html 标签,像上一章的例子那样是一个普通的 div,则会实例化一个普通 VNode 节点,否则通过 createComponent 方法创建一个组件 VNode。
在scr/core/vnode/create-elements.js
if (typeof tag === 'string') {
let Ctor
ns = (context.$vnode && context.$vnode.ns) || config.getTagNamespace(tag)
if (config.isReservedTag(tag)) {
// platform built-in elements
vnode = new VNode(
config.parsePlatformTagName(tag), data, children,
undefined, undefined, context
)
} else if (isDef(Ctor = resolveAsset(context.$options, 'components', tag))) {
// component
vnode = createComponent(Ctor, data, context, children, tag)
} else {
// unknown or unlisted namespaced elements
// check at runtime because it may get assigned a namespace when its
// parent normalizes children
vnode = new VNode(
tag, data, children,
undefined, undefined, context
)
}
} else {
// direct component options / constructor
vnode = createComponent(tag, data, context, children)
}
在我们这一章传入的是一个 App 对象,它本质上是一个 Component 类型,那么它会走到上述代码的 else 逻辑,直接通过 createComponent 方法来创建 vnode。所以接下来我们来看一下 createComponent 方法的实现,它定义在 src/core/vdom/create-component.js 。
3.createComponent 方法
在src/core/vdom/create-component.js中:
export function createComponent (
//可以是组件类型的类,函数或者对象
Ctor: Class<Component> | Function | Object | void,
// VNode(虚拟DOM)的相关Data
data: ?VNodeData,
// 上下文,也就是我们的当前的Vue实例---vm
context: Component,
// 组件的子VNode
children: ?Array<VNode>,
tag?: string
): VNode | Array<VNode> | void {
if (isUndef(Ctor)) {
return
}
const baseCtor = context.$options._base
// plain options object: turn it into a constructor
if (isObject(Ctor)) {
Ctor = baseCtor.extend(Ctor)
}
// if at this stage it's not a constructor or an async component factory,
// reject.
if (typeof Ctor !== 'function') {
if (process.env.NODE_ENV !== 'production') {
warn(`Invalid Component definition: ${String(Ctor)}`, context)
}
return
}
// async component
let asyncFactory
if (isUndef(Ctor.cid)) {
asyncFactory = Ctor
Ctor = resolveAsyncComponent(asyncFactory, baseCtor, context)
if (Ctor === undefined) {
// return a plac