vue源码阅读记录5-createComponent(1)
一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第14天,点击查看活动详情。
开始
在上篇$mount文章中,提到了createElement 这个函数,通过这个创建并返回vnode,现在我们再看看这个创建的vnode的来源是哪里,在平时开发中我们经常会使用到components引入组件,并通过模版渲染,今天就看下如果通过这个方式去实现的组件。
在createElement方法中能定位到_createElement.我定位到了这句话
...
} else if ((!data || !data.pre) && isDef(Ctor = resolveAsset(context.$options, 'components', tag))) {
// component
vnode = createComponent(Ctor, data, context, children, tag)
} else {
...
这个就是我们通过components
来创建的虚拟dom,点进去发现他在src/core/vdom/create-component.js
这个文件中。
export function createComponent (
Ctor: Class<Component> | Function | Object | void,
data: ?VNodeData,
context: Component,
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)
if (Ctor === undefined) {
// return a placeholder node for async component, which is rendered
// as a comment node but preserves all the raw information for the node.
// the information will be used for async server-rendering and hydration.
return createAsyncPlaceholder(
asyncFactory,
data,
context,
children,
tag
)
}
}
data = data || {}
// resolve constructor options in case global mixins are applied after
// component constructor creation
resolveConstructorOptions(Ctor)
// transform component v-model data into props & events
if (isDef(data.model)) {
transformModel(Ctor.options, data)
}
// extract props
const propsData = extractPropsFromVNodeData(data, Ctor, tag)
// functional component
if (isTrue(Ctor.options.functional)) {
return createFunctionalComponent(Ctor, propsData, data, context, children)
}
// extract listeners, since these needs to be treated as
// child component listeners instead of DOM listeners
const listeners = data.on
// replace with listeners with .native modifier
// so it gets processed during parent component patch.
data.on = data.nativeOn
if (isTrue(Ctor.options.abstract)) {
// abstract components do not keep anything
// other than props & listeners & slot
// work around flow
const slot = data.slot
data = {}
if (slot) {
data.slot = slot
}
}
// install component management hooks onto the placeholder node
installComponentHooks(data)
// return a placeholder vnode
const name = Ctor.options.name || tag
const vnode = new VNode(
`vue-component-${Ctor.cid}${name ? `-${name}` : ''}`,
data, undefined, undefined, undefined, context,
{ Ctor, propsData, listeners, tag, children },
asyncFactory
)
// Weex specific: invoke recycle-list optimized @render function for
// extracting cell-slot template.
// https://github.com/Hanks10100/weex-native-directive/tree/master/component
/* istanbul ignore if */
if (__WEEX__ && isRecyclableComponent(vnode)) {
return renderRecyclableComponentTemplate(vnode)
}
return vnode
}
刚刚读这块的时候一脸蒙,啥啥啥,都是讲的啥?
先看 Ctor
这个对象,可以看到他是由``(Ctor = resolveAsset(context.$options, 'components', tag)```解析出来的一个对象。
const baseCtor = context.$options._base
这句话的_base又是从哪里来的。可以在init的时候绑定$options的函数,resolveConstructorOptions(vm.constructor)
,具体的就不往里面看了,可以自行的了解下,_base具体的作用就是拿到 Vue 这个构造函数。
了解Ctor后,继续看Ctor = baseCtor.extend(Ctor)
,出现了一个extend函数。src/core/global-api/extend.js
这里面会有extends的函数介绍。这边简单的讲就是构造一个vue的子类,返回构造器sub,并且对这个sub进行了一些opstions的扩展,和api的添加、初始化props和compued。而且做了一个避免重复构造的判断,所以在实例化sub的时候,就会执行_init逻辑,再次走到了vue初始化的方法,这也是为什么组件都是有自己的生命周期.
总结
这边太过复杂,必须仔细整理每个函数的逻辑和用途,读不下去也要继续坚持,熬过来就好了!