Vue3组件初始化流程(四): 解决todo:applyOptions对Vue2写法的兼容 initProps Slots [Vue3源码系列_xiaolu]


theme: vuepress
highlight: androidstudio

解决todo

这一章我们来解决前面留下的部分todo

getExposeProxy

getExposeProxy方法 路径: core\packages\runtime-core\src\component.ts

export function getExposeProxy(instance: ComponentInternalInstance) {
  // 判断exposed是否存在
  if (instance.exposed) {
    //todo To: 返回通过proxyRefs 和markRaw处理的
    return (
      instance.exposeProxy ||
      (instance.exposeProxy = new Proxy(proxyRefs(markRaw(instance.exposed)), {
        get(target, key: string) {
          if (key in target) {
            return target[key]
          } else if (key in publicPropertiesMap) {
            return publicPropertiesMap[key](instance)
          }
        }
      }))
    )
  }
}

才看一步,我们又看到了proxyRefs和markRaw(涉及响应式),因此留下todo

createSetupContext

createSetupContext方法 路径: core\packages\runtime-core\src\component.ts

export function createSetupContext(
  instance: ComponentInternalInstance
): SetupContext {
  // 初始化expose
  const expose: SetupContext['expose'] = exposed => {
    instance.exposed = exposed || {}
  }

  let attrs: Data
  if (__DEV__) {

  } else {
    // 返回包含attrs slots emit expose的对象
    return {
      get attrs() {
        return attrs || (attrs = createAttrsProxy(instance))
      },
      slots: instance.slots,
      emit: instance.emit,
      expose
    }
  }
}

createSetupContext方法做了什么?

功能: 返回一个包含attrs slots emit expose的对象,也就是我们使用的setup的第二个参数

对这个方法的分析我都写在了注释上,因为涉及太多的方法跳转

这一步的注释在 初始化setupContext

initProps

initProps方法 路径: core\packages\runtime-core\src\componentProps.ts

export function initProps(
  instance: ComponentInternalInstance,
  rawProps: Data | null,
  isStateful: number, // result of bitwise flag comparison
  isSSR = false
) {
  const props: Data = {}
  const attrs: Data = {}
  def(attrs, InternalObjectKey, 1)

  instance.propsDefaults = Object.create(null)

  setFullProps(instance, rawProps, props, attrs)

  // ensure all declared prop keys are present
  for (const key in instance.propsOptions[0]) {
    if (!(key in props)) {
      props[key] = undefined
    }
  }

  if (isStateful) {
    // stateful
    instance.props = isSSR ? props : shallowReactive(props)
  } else {
    if (!instance.type.props) {
      // functional w/ optional props, props === attrs
      instance.props = attrs
    } else {
      // functional w/ declared props
      instance.props = props
    }
  }
  instance.attrs = attrs
}

initProps方法做了什么?

功能: 初始化并拆分props、attrs,并对default做了处理,prop大小写进行了处理

对这个方法的分析我都写在了注释上(和initSlots在一起),因为涉及太多的方法跳转

initSlots

initSlots方法 路径: core\packages\runtime-core\src\componentSlots.ts

export const initSlots = (
  instance: ComponentInternalInstance,
  children: VNodeNormalizedChildren
) => {
  if (instance.vnode.shapeFlag & ShapeFlags.SLOTS_CHILDREN) {
    const type = (children as RawSlots)._
    if (type) {
      // users can get the shallow readonly version of the slots object through `this.$slots`,
      // we should avoid the proxy object polluting the slots of the internal instance
      instance.slots = toRaw(children as InternalSlots)
      // make compiler marker non-enumerable
      def(children as InternalSlots, '_', type)
    } else {
      normalizeObjectSlots(
        children as RawSlots,
        (instance.slots = {}),
        instance
      )
    }
  } else {
    instance.slots = {}
    if (children) {
      normalizeVNodeSlots(instance, children)
    }
  }
  def(instance.slots, InternalObjectKey, 1)
}

initSlots方法做了什么?

功能: 初始化slots

这一步注释在: initProps和initSlots

applyOptions

applyOptions方法 路径: core\packages\runtime-core\src\componentOptions.ts

export function applyOptions(instance: ComponentInternalInstance) {

  const options = resolveMergedOptions(instance)
  const publicThis = instance.proxy! as any
  const ctx = instance.ctx

  shouldCacheAccess = false

  if (options.beforeCreate) {
    callHook(options.beforeCreate, instance, LifecycleHooks.BEFORE_CREATE)
  }

  const {

    data: dataOptions,
    computed: computedOptions,
    methods,
    watch: watchOptions,
    provide: provideOptions,
    inject: injectOptions,

    created,
    beforeMount,
    mounted,
    beforeUpdate,
    updated,
    activated,
    deactivated,
    beforeDestroy,
    beforeUnmount,
    destroyed,
    unmounted,
    render,
    renderTracked,
    renderTriggered,
    errorCaptured,
    serverPrefetch,
    // public API
    expose,
    inheritAttrs,
    // assets
    components,
    directives,
    filters
  } = options


  if (injectOptions) {}

  if (methods) {}

  if (dataOptions) {}

  shouldCacheAccess = true

  if (computedOptions) {}
  
  if (watchOptions) {}

  if (provideOptions) {}

  if (created) {
    callHook(created, instance, LifecycleHooks.CREATED)
  }

  function registerLifecycleHook(
    register: Function,
    hook?: Function | Function[]
  ) {
    if (isArray(hook)) {
      hook.forEach(_hook => register(_hook.bind(publicThis)))
    } else if (hook) {
      register((hook as Function).bind(publicThis))
    }
  }

  registerLifecycleHook(onBeforeMount, beforeMount)
  registerLifecycleHook(onMounted, mounted)
  registerLifecycleHook(onBeforeUpdate, beforeUpdate)
  registerLifecycleHook(onUpdated, updated)
  registerLifecycleHook(onActivated, activated)
  registerLifecycleHook(onDeactivated, deactivated)
  registerLifecycleHook(onErrorCaptured, errorCaptured)
  registerLifecycleHook(onRenderTracked, renderTracked)
  registerLifecycleHook(onRenderTriggered, renderTriggered)
  registerLifecycleHook(onBeforeUnmount, beforeUnmount)
  registerLifecycleHook(onUnmounted, unmounted)
  registerLifecycleHook(onServerPrefetch, serverPrefetch)

  if (isArray(expose)) {}

  if (render && instance.render === NOOP) {}
  if (inheritAttrs != null) {}

  if (components) instance.components = components as any
  if (directives) instance.directives = directives
}

applyOptions方法做了什么?

功能: 这是对Vue2.0写法进行兼容处理

  1. data的处理就是将data调用之后的结果进行reactive包裹进行响应式处理
  2. methods的处理就是遍历给methods修改this指向
  3. computed的处理就是通过computed包裹,并且处理get、set的情况
  4. 以及其他更多方法都写在了注释里

只要知道对Vue2的写法兼容是在这个applyOptions方法里完成的就行了

这次的注释在applyOptions

剩下的todo

解决了这几个todo之后,现在来看剩下的todo,如图

Vue3组件初始化流程(四): 解决todo:applyOptions对Vue2写法的兼容 initProps Slots [Vue3源码系列_xiaolu]_第1张图片

可以看到,现在的todo都指向了一个模块: reactivity(响应式模块)

是的,这也是我们接下来的目标,响应式

到此,Vue3组件初始化流程完结,敬请期待下一期的Vue3响应式模块

你可能感兴趣的:(vue,源码,vue.js,源码,typescript)