Skip to content

11 - 组件化 (createComponent 的实现) - part 2 #11

@chenfaxiang

Description

@chenfaxiang

createComponent

上一部分学习到了 createComponent 方法是在哪个地方因为什么条件进行了调用,这里来继续深入,看一看 createComponent 的具体实现是怎样的,其定义在 /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
  }

  // 这里得到的是 Vue,而 $options._base 哪里来的?
  // $options._base 在 /src/core/global-api/index.js 初始化函数 initGlobalAPI 中定义
  // Vue.options._base = Vue
  // 这里的 Vue.options 和 context.$options 连名字都不一样,这就是同一个东西?
  // omg,options 和 $options 到底是怎么关联的?找吧
  // 在文件 /src/core/instance/init.js 定义 _init 方法的时候有这样一个操作。。
  /**
   * // merge options —— 合并配置
   * if (options && options._isComponent) {
   *  // optimize internal component instantiation
   *  // since dynamic options merging is pretty slow, and none of the
   *  // internal component options needs special treatment.
   *  initInternalComponent(vm, options)
   * } else {
   *   vm.$options = mergeOptions(
   *   resolveConstructorOptions(vm.constructor),
   *   options || {},
   *   vm
   *  )
   * }
  **/
  const baseCtor = context.$options._base

  // plain options object: turn it into a constructor
  // 构造子类构造函数
 if (isObject(Ctor)) {
    // 这里 baseCtor.extend 就等价于 Vue.extend()
    // extend() 方法在哪里定义的?主要逻辑是干什么?
    // /src/core/global-api/extend.js 文件中定义了方法 Vue.extend()
    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 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

  // 实例化 VNode
  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
}

这里有几部分比较重点,通过标注进行了解释,包括:构造子类构造函数、安装组件钩子函数、实例化 vnode

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions