vue源码阅读记录5-createComponent(1)

142 阅读2分钟

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初始化的方法,这也是为什么组件都是有自己的生命周期.

总结

这边太过复杂,必须仔细整理每个函数的逻辑和用途,读不下去也要继续坚持,熬过来就好了!