溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Vue2中Provide?Inject依賴注入源碼分析

發(fā)布時間:2022-08-26 11:44:37 來源:億速云 閱讀:145 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容介紹了“Vue2中Provide Inject依賴注入源碼分析”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!

    Provide/Inject 初始化

    1. initInjections 依賴初始化

    該步驟其實發(fā)生在 initState 之前,但是由于 provide/inject 一般是配合使用,所以這里調(diào)整了一下順序。

    該函數(shù)的定義與過程都比較簡單:

    export function initInjections(vm: Component) {
      const result = resolveInject(vm.$options.inject, vm)
      if (result) {
        toggleObserving(false)
        Object.keys(result).forEach(key => {
          if (__DEV__) {
            defineReactive(vm, key, result[key], () => warn(''))
          } else {
            defineReactive(vm, key, result[key])
          }
        })
        toggleObserving(true)
      }
    }
    export function resolveInject(inject: any, vm: Component): Record<string, any> | undefined | null {
      if (inject) {
        const result = Object.create(null)
        const keys = hasSymbol ? Reflect.ownKeys(inject) : Object.keys(inject)
    
        for (let i = 0; i < keys.length; i++) {
          const key = keys[i]
          if (key === '__ob__') continue
          const provideKey = inject[key].from
          if (provideKey in vm._provided) {
            result[key] = vm._provided[provideKey]
          } else if ('default' in inject[key]) {
            const provideDefault = inject[key].default
            result[key] = isFunction(provideDefault) ? provideDefault.call(vm) : provideDefault
          } else if (__DEV__) {
            warn('')
          }
        }
        return result
      }
    }
    • 在 initInjections 函數(shù)中,只是遍歷了 options.inject 配置的依賴數(shù)據(jù),并 關(guān)閉 了依賴數(shù)據(jù)的 響應(yīng)式依賴收集,最后通過 defineReactive 將對應(yīng)的數(shù)據(jù)掛載到實例 vm 上,以便后面能直接訪問。

    這就是官方提示的 為什么 provide/inject 的數(shù)據(jù)不是響應(yīng)式的了。

    • 而 resolveInject 函數(shù)就是用來對組件的 inject 依賴數(shù)據(jù)進行處理,并返回一個沒有多余原型鏈的對象。

    在官方文檔中,inject 接收一個字符串?dāng)?shù)組或者一個 key 為 string 的對象,而作為對象時則 必須 有 from 字段來表示依賴數(shù)據(jù)的獲取指向,另外也接收一個 default 屬性作為降級時使用的默認值。

    但是,在 mergeOptions 之后,會將 options.inject 轉(zhuǎn)為標(biāo)準(zhǔn)對象格式。

    并且這里并沒有對注入數(shù)據(jù) provide[key] 進行處理,而是直接賦值;所以才有:如果你傳入了一個可監(jiān)聽的對象,那么其對象的 property 還是可響應(yīng)的。

    resolveInject() 函數(shù)就是解析標(biāo)準(zhǔn)格式 inject 配置,并將上層組件的 provide 的值或者 default 默認值綁定到函數(shù)返回對象中;如果這兩個都沒有,則會提示錯誤信息 “injection xx not found”

    2. initProvide 注入數(shù)據(jù)初始化

    初始化注入數(shù)據(jù)的過程也很簡單,整個過程其實與 initInjection 類似。其函數(shù)定義如下:

    export function initProvide(vm: Component) {
      const provideOption = vm.$options.provide
      if (provideOption) {
        const provided = isFunction(provideOption) ? provideOption.call(vm) : provideOption
        if (!isObject(provided)) {
          return
        }
        const source = resolveProvided(vm)
        
        const keys = hasSymbol ? Reflect.ownKeys(provided) : Object.keys(provided)
        for (let i = 0; i < keys.length; i++) {
          const key = keys[i]
          Object.defineProperty(
            source,
            key,
            Object.getOwnPropertyDescriptor(provided, key)!
          )
        }
      }
    }
    export function resolveProvided(vm: Component): Record<string, any> {
      const existing = vm._provided
      const parentProvides = vm.$parent && vm.$parent._provided
      if (parentProvides === existing) {
        return (vm._provided = Object.create(parentProvides))
      } else {
        return existing
      }
    }

    官方文檔中對 provide 配置項的說明是,可以是一個對象或者一個返回對象的函數(shù)。

    • 所以這里首先判斷了 options.provide 的類型并獲取到了結(jié)果,如果結(jié)果 不是對象則會直接退出。

    • 然后,則是初始化 provide 的數(shù)據(jù)。

    此時會將當(dāng)前實例的 provided 數(shù)據(jù)與父組件實例的 provided 進行比較,如果相同,則返回一個 以父組件實例 provided 數(shù)據(jù)為原型創(chuàng)建的對象,否則直接返回當(dāng)前實例的 provided 數(shù)據(jù)。

    因為每一個實例都會進行與父組件實例的注入數(shù)據(jù)比較,所以才能多層級傳遞

    • 最后,則是遍歷 provided 對象,通過 Object.defineProperty 來處理數(shù)據(jù)獲取。

    “Vue2中Provide Inject依賴注入源碼分析”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

    向AI問一下細節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI