@vue/composition-api análise de princípios

prefácio

O artigo anterior apresentou o que é @vue/composition-api e porque deve ser usado. Agora vamos analisar sistematicamente o princípio de implementação de @vue/composition-api, esperando aprofundar a compreensão de seu mecanismo de funcionamento.

As regras antigas compartilham primeiro a avaliação da IA: a introdução ao princípio de implementação de @vue/composition-api é muito detalhada e precisa em geral, mostrando o código principal e a lógica da chave, o que fornece uma boa análise para entender seu funcionamento mecanismo.

Análise de código principal

instalar

Ao introduzir @vue/composition-api, você precisa chamar manualmente a instalação do plug-in por meio de Vue.use(), então vamos ver o que é feito durante a instalação:


export function install(Vue: VueConstructor) {
    
    
  setVueConstructor(Vue)
  mixin(Vue)
}

A coisa mais importante aqui é, na verdade, a função mixin, que define o gancho beforeCreate para executar a inicialização,
construir props e objetos ctx de contexto e executar a função de configuração:

export function mixin(Vue: VueConstructor) {
    
    
  Vue.mixin({
    
    
    beforeCreate: functionApiInit,
    mounted(this: ComponentInstance) {
    
    
      afterRender(this)
    },
    beforeUpdate() {
    
    
      updateVmAttrs(this as ComponentInstance)
    },
    updated(this: ComponentInstance) {
    
    
      afterRender(this)
    },
  })
  function functionApiInit(this: ComponentInstance) {
    
    
    const vm = this
    const $options = vm.$options
    const {
    
     setup, render } = $options

    const {
    
     data } = $options
    // wrapper the data option, so we can invoke setup before data get resolved
    $options.data = function wrappedData() {
    
    
      // 在data周期时,进行setup函数的执行
      initSetup(vm, vm.$props)
	  return data || {
    
    }
    }
  }

  function initSetup(vm: ComponentInstance, props: Record<any, any> = {
     
     }) {
    
    
    const setup = vm.$options.setup!
    // 构造ctx对象,有以下key:
    // slots: 组件的插槽,默认为 {}
    // root: 组件的根实例
    // parent: 组件的父实例
    // refs: 组件的 ref 引用
    // listeners: 组件的事件监听器
    // isServer: 是否是服务端渲染
    // ssrContext: 服务端渲染的上下文
    // emit: 组件的自定义事件触发函数
    const ctx = createSetupContext(vm)
    const instance = toVue3ComponentInstance(vm)
    instance.setupContext = ctx

    // 通过Vue.observable对props进行响应式监听
    def(props, '__ob__', createObserver())
  }
}

ref

A função ref pode converter um valor comum em dados responsivos. Ele retorna um objeto ref mutável, e um atributo .value é montado no objeto.Podemos ler ou modificar o valor de ref através deste atributo .value.

Sua essência ainda é responsiva baseada em reativo, mas um pré-pacote de get e set é feito. O código fonte é o seguinte:

export function ref(raw?: unknown) {
    
    
  // ref的本质其实还是调用的reactive
  // 然后通过 get/set 方法操作这个对象的值来实现对 ref 值的跟踪和响应
  const value = reactive({
    
     [RefKey]: raw })
  return createRef({
    
    
    get: () => value[RefKey] as any,
    set: (v) => ((value[RefKey] as any) = v),
  })
}

createRef é finalmente baseado em Object.defineProperty:

export function proxy(
  target: any,
  key: string,
  {
     
      get, set }: {
     
      get?: Function; set?: Function }
) {
    
    
  Object.defineProperty(target, key, {
    
    
    enumerable: true,
    configurable: true,
    get: get || noopFn,
    set: set || noopFn,
  })
}

reativo

A camada inferior é baseada em Vue.observable para estabelecer monitoramento responsivo. A implementação de Vue.observable em Vue2 e Vue3 é diferente:

export function reactive<T extends object>(obj: T): UnwrapRef<T> {
    
    
  // 基于Vue.observable
  const observed = observe(obj)
  setupAccessControl(observed)
  return observed as UnwrapRef<T>
}

calculado

A função computada é usada para criar uma propriedade computada que é armazenada em cache e executada lentamente com base nas dependências.

Crie funções get e set e monitore e vincule através do objeto Watcher do Vue.

export function computed<T>(
  getterOrOptions: ComputedGetter<T> | WritableComputedOptions<T>
): ComputedRef<T> | WritableComputedRef<T> {
    
    
  const vm = getCurrentScopeVM()
  let getter: ComputedGetter<T>
  let setter: ComputedSetter<T> | undefined

  getter = getterOrOptions.get
  setter = getterOrOptions.set

  let computedSetter
  let computedGetter
  const {
    
     Watcher, Dep } = getVueInternalClasses()
  let watcher: any
  computedGetter = () => {
    
    
    if (!watcher) {
    
    
      watcher = new Watcher(vm, getter, noopFn, {
    
     lazy: true })
    }
    if (watcher.dirty) {
    
    
      watcher.evaluate()
    }
    if (Dep.target) {
    
    
      watcher.depend()
    }
    return watcher.value
  }

  computedSetter = (v: T) => {
    
    
    if (setter) {
    
    
      setter(v)
    }
  }
  return createRef<T>(
    {
    
    
      get: computedGetter,
      set: computedSetter,
    },
    !setter,
    true
  ) as WritableComputedRef<T> | ComputedRef<T>
}

assistir

A função de observação é usada para ouvir uma fonte de dados específica e executar efeitos colaterais na função de retorno de chamada.

A camada inferior é implementada através do Vue.$watch:

// 底层是通过Vue.$watch来实现
function createVueWatcher(
  vm: ComponentInstance,
  getter: () => any,
  callback: (n: any, o: any) => any,
  options: {
    
    
    deep: boolean
    sync: boolean
    immediateInvokeCallback?: boolean
    noRun?: boolean
    before?: () => void
  }
): VueWatcher {
    
    
  const index = vm._watchers.length
  // @ts-ignore: use undocumented options
  vm.$watch(getter, callback, {
    
    
    immediate: options.immediateInvokeCallback,
    deep: options.deep,
    lazy: options.noRun,
    sync: options.sync,
    before: options.before,
  })

  return vm._watchers[index]
}

toRefs

toRefs pode converter as propriedades de um objeto reativo em forma de referência.

A camada inferior é para percorrer as chaves uma a uma para chamar toRef e, em seguida, manter a capacidade de resposta com base em createRef:

export function toRef<T extends object, K extends keyof T>(
  object: T,
  key: K
): Ref<T[K]> {
    
    
  if (!(key in object)) set(object, key, undefined)
  const v = object[key]
  if (isRef<T[K]>(v)) return v

  return createRef({
    
    
    get: () => object[key],
    set: (v) => (object[key] = v),
  })
}

vida útil

O tempo de vida é na verdade uma substituição temporária:

// 利用 Vue 的选项合并策略(option merge strategies),
// 通过给组件实例的 $options 注入自定义的生命周期hook函数,来override原有的生命周期选项。

// 生命周期hook函数需要通过 getCurrentInstance() 获取当前活跃的组件实例,
// 并在执行回调前通过 setCurrentInstance()绑定实例,在回调执行完毕后恢复之前的实例。

export const onBeforeMount = createLifeCycle('beforeMount')
export const onMounted = createLifeCycle('mounted')
export const onBeforeUpdate = createLifeCycle('beforeUpdate')
export const onUpdated = createLifeCycle('updated')
export const onBeforeUnmount = createLifeCycle('beforeDestroy')
export const onUnmounted = createLifeCycle('destroyed')
export const onErrorCaptured = createLifeCycle('errorCaptured')
export const onActivated = createLifeCycle('activated')
export const onDeactivated = createLifeCycle('deactivated')
export const onServerPrefetch = createLifeCycle('serverPrefetch')

Acho que você gosta

Origin blog.csdn.net/mevicky/article/details/132057855
Recomendado
Clasificación