# createComponent

# createComponent

  • 创建组件的VNode
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
    // Vue.extend
    const baseCtor = context.$options._base
    // 当 Ctor 为配置对象时,通过 Vue.extend 将其转为构造函数
    if (isObject(Ctor)) {
        Ctor = baseCtor.extend(Ctor)
    }
    // 如果到这个为止,Ctor仍然不是一个函数,则表达式是一个无效的组件定义
    if (typeof Ctor !== 'function') return
    
    // 异步组件
    let asyncFactroy
    if (isUndef(Ctor.cid)) {
        asyncFactroy = Ctor
        Ctor = resolveAsyncComponent(asyncFactory, baseCtor)
        if (Ctor === undefined) {
            // 为异步组件返回一个占位符节点
            return createAsyncPlaceholder(
                asyncFactory,
                data,
                context,
                children,
                tag
            )
        }
    }
    
    // 节点的属性 JSON 字符串
    data = data || {}
    
    // 这里其实就是组件做选项合并的地方 下方
    resolveConstructorOptions(Ctor)
    
    // 将组件的 v-model 信息 转换为 data.attrs
    if (isDef(data.model)) {
        transformModel(Ctor.options, data)
    }
    
    // 从 attrs 中提取 props 数据, 得到 propsData 对象
    const propsData = extractPropsFromVNodeData(data, Ctor, tag)
    
    // 函数式组件
    if (isTrue(Ctor.options.functional)) {
        return createFunctionalComponent(Ctor, propsData, data, context, children)
    }
    // 获取事件监听器对象 data.on
    const listeners = data.on
    data.on = data.nativeOn
    
    if (isTrue(Ctor.options.abstract)) {
        // 如果是抽象组件,则保留props,listeners和slot
        const slot = data.slot
        data = {}
        if (slot) {
            data.slot = slot
        }
    }
    
    // 在组件的 data 对象上设置 hook 对象
    // hook 对象增加四个属性, init、prepatch、insert、destroy
    // init 会为 VNode.conponentInstance 创建 对应 vue 实例
    installComponentHooks(data)
    
    const name = Ctor.options.name || tag
    const vnode = new VNode(
        `vue-component-${Ctor.id}${name ? `-${name}` : ''}`,
        data, undefined, undefined, undefined, context,
        { Ctor, propsData, listeners, tag, children },
        asyncFactory
    )
    if (__WEEX__ && isRecyclableComponent(vnode)) {
        return renderRecyclableComponentTemplate(vnode)
    }
    return vnode
}

resolveConstructorOptions 与 resloveModifiedOptions

  • 应该是处理 Vue.extend 的 Ctor
export function resolveConstructorOptions(Ctor: Class<Component>) {
    // 从实例构造函数上获取选项
    let options = Ctor.options
    if (Ctor.super) {
        // 递归处理所有的父级
        const superOptions = resolveConstructorOptions(Ctor.super)
        const cachedSuperOptions = Ctor.superOptions
        if (superOptions !== cachedSuperOptions) {
            // 基类的配置项发生了更改
            Ctor.superOptions = superOptions
            const modifiedOptions = resolveModifiedOptions(Ctor)
            if (modifiedOptions) {
                // 将更改的选项合并
                extend(Ctor.extendOptions, modifiedOptions)
            }
            options = Ctor.options = mergeOption(superOptions, Ctor.extendOptions)
            if (options.name) {
                options.components[options.name] = Ctor
            }
        }
    }
    return options
}

function resolveModifiedOptions (Ctor: Class<Component>)?: Object {
    let modified
    const latest = Cotr.options
    const sealed = Ctor.sealeOptions
    // 将 latest 与 sealed 中不相同的放入 modified 返回
    for (const key in latest) {
        if (last[key] !== sealed[key]) {
            if (!modified) modified = {}
            modified[key] = latest[key]
        }
    }
    return modified
}

transformModel

  • 将组件的 v-model 转换为 data.attrs 对象属性和 data.on 对象上的事件
function transformModel(options, data) {
    const prop = (options.model && options.model.prop) || 'value'
    const event = (options.model && options.model.event) || 'input'
    ; (data.attrs || (data.attrs = {}))[prop] = data.model.value
    const on = data.on || (data.on = {})
    // 获取对应的 event 已存在的事件
    const existing = on[event]
    const callback = data.model.callback
    if (isDef(existing)) {
        if (
            Array.isArray(existing)
                ? existing.indexOf(callback) === -1
                : existing !== callback
        ) {
            // 如果是个数组 合并回调函数
            on[event] = [callback].concat(existing)
        } else {
            on[event] = callback
        }
    }
}

extractPropsFromVNodeData

// 处理 attrs 与 props
export function extractPropsFromVNodeData (
    data: VNodeData,
    Ctor: Class<Component>,
    tag?: tag
): ?Object {
    const propOptions = Ctor.options.props
    // 未定义 props 直接返回
    if (isUndef(propOptions)) return
    
    const res = {}
    const { attrs, props } = data
    if (isDef(attrs) || isDef(props)) {
        for (const key in propOptions) {
            // 将小驼峰的 key 转换为 连字符 形式
            const altKey = hyphenate(key)
            checkProp(res, props, key, altKey, true) ||
            checkProp(res, attrs, key, altKey, false)
        }
    }
    return res
}

function checkProp (
    res: Object,
    hash: ?Object,
    key: string,
    altKey: string,
    preserve: boolean
): boolean {
    if (isDef(hash)) {
        if (hasOwn(hash, key)) {
            res[key] = has[key]
            if (!preserve) delete hash[key]
            return true
        } else if (hasOwn(hash, altKey)) {
            res[key] = hash(altKey)
            if (!preserve) delete hash[altKey]
            return true
        }
    }
    return false
}

# createFunctionalComponent