【Vue2 源码06】组件

127 阅读1分钟

Vue.component

// file: scr/core/global-api/assets.js

if (type === 'component' && isPlainObject(definition)) {
    definition.name = definition.name || id
    definition = this.options._base.extend(definition)
}
this.options[type + 's'][id] = definition // 下面extend后挂载到这

Vue.extend

// file: scr/core/global-api/extend.js

Vue.extend = function (extendOptions: Object): Function{
    // 1. 初始化、检查参数
    extendOptions = extendOptions || {}
    const Super = this
    const SuperId = Super.cid
    const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
    if (cachedCtors[SuperId]) {
      // 设置缓存,防止多次注册
      return cachedCtors[SuperId]
    }
    const name = extendOptions.name || Super.options.name
    if (process.env.NODE_ENV !== 'production' && name) {
      validateComponentName(name)
    }
    
    // 2. 构造原型链、设置构造函数选项
    const Sub = function VueComponent (options) {
      this._init(options)
    }
    Sub.prototype = Object.create(Super.prototype)
    Sub.prototype.constructor = Sub
    Sub.cid = cid++
    Sub.options = mergeOptions(
      Super.options,
      extendOptions
    )
    Sub['super'] = Super
    
    // 3. 原型代理,避免组件实例多次proxy
    if (Sub.options.props) {
      initProps(Sub)
    }
    if (Sub.options.computed) {
      initComputed(Sub)
    }
    
    // 4. 继承全局方法、组件
    Sub.extend = Super.extend
    Sub.mixin = Super.mixin
    Sub.use = Super.use
    ASSET_TYPES.forEach(function (type) {
      Sub[type] = Super[type]
    })
    if (name) {
      Sub.options.components[name] = Sub
    }
    
    // 5. 保留原选项并返回
    Sub.superOptions = Super.options
    Sub.extendOptions = extendOptions
    Sub.sealedOptions = extend({}, Sub.options)

    cachedCtors[SuperId] = Sub
    return Sub
}

vm._update

createComponent

function createComponent (vnode, insertedVnodeQueue, parentElm, refElm) {
    let i = vnode.data
    if (isDef(i)) {
        // keepAlive 包裹
        const isReactivated = isDef(vnode.componentInstance) && i.keepAlive
        if (isDef(i = i.hook) && isDef(i = i.init)) {
        // 调用data.hook.init 初始化组件
            i(vnode, false /* hydrating */)
        }
        // 必然设置了vnode.componentInstance
        if (isDef(vnode.componentInstance)) {
            initComponent(vnode, insertedVnodeQueue)
            insert(parentElm, vnode.elm, refElm)
            if (isTrue(isReactivated)) {
                reactivateComponent(vnode, insertedVnodeQueue, parentElm, refElm)
            }
            return true
        }
    }
}

initComponent

function initComponent (vnode, insertedVnodeQueue) {
    if (isDef(vnode.data.pendingInsert)) {
        insertedVnodeQueue.push.apply(insertedVnodeQueue, vnode.data.pendingInsert)
        vnode.data.pendingInsert = null
    }
    vnode.elm = vnode.componentInstance.$el // 组件在createElm中创建的elment
    if (isPatchable(vnode)) {
        invokeCreateHooks(vnode, insertedVnodeQueue)
        setScope(vnode)
    } else {
        registerRef(vnode)
        insertedVnodeQueue.push(vnode)
    }
}

invokeCreateHooks

function invokeCreateHooks (vnode, insertedVnodeQueue) {
    for (let i = 0; i < cbs.create.length; ++i) {
        cbs.create[i](emptyNode, vnode)
    }
    i = vnode.data.hook // Reuse variable
    if (isDef(i)) {
        if (isDef(i.create)) i.create(emptyNode, vnode)
        if (isDef(i.insert)) insertedVnodeQueue.push(vnode)
    }
}