小菜鳥之Vue - provide/inject不歸路

前言

爲何我要寫這麼一篇文章,網上不是一堆關於provide/inject的技術文章嗎? 緣由在於網上的那些博客大牛文章能完美避開坑,而我這篇文章描述是挖坑和埋坑的一個過程html

provide/inject是什麼

依賴注入,官網的描述並不能阻止我不寫這個文章,緣由很簡單,官網只是老菜鳥的隨手備忘錄,小菜鳥還須要成長磨礪,它不能解決我一些問題。vue

什麼時候使用

父子組件交互方式多種,props、vuex、$refs、$emit、localStorage還有就是這個provide/inject了。它適合層級比較深的組件,好比子,子孫,子孫後代的組件有好幾個用到父組件的某個屬性,就能夠用到這個provide/inject,它能夠避免寫大量繁瑣的傳值代碼
我這裏爲何要使用它? 我一個知識庫詳情父組件中包含了大量的子組件,每一個子組件都須要父組件的知識庫ID,這時候我不想寫大量props,就用到provide/inject進行傳值了web

響應式傳值最終版

急躁的改寫這個代碼結構就能夠完成provide/inject響應傳值vuex

data() {
      return {
        knowledge: {
          knowledgeId: ''
        }
      }
    },
    provide() {
      return {
        // 直接傳對象
        kData: this.knowledge
      }
    },
    created() {
      // 變動data屬性knowledge下的knowledgeId元素值
      this.knowledge.knowledgeId = 2
    }

子組件使用webstorm

inject: ['kData'],
    mounted() {
      console.error('yc:' + this.kData.knowledgeId)
    }

坑在哪

坑在於provide,子組件inject沒什麼難度ide

  • 初版嘗試

下面代碼並不能在子組件獲取這個kId的值,但網上有provide: {}這樣定義的寫法,他們之因此可以成功是kId: 'xxx'後面定義的是一個靜態的字符串而不是動態的獲取data中的knowledgeId屬性函數

data() {
      return {
        knowledgeId: 1
      }
    },
    provide: {
      kId: this.knowledgeId
    }
  • 第二版嘗試

上面初版的問題很好解決,網上有另一種寫法就是經過provide函數返回一個對象,這種是能夠獲取到data中的屬性內容工具

data() {
      return {
        knowledgeId: 1
      }
    },
    provide() {
      return {
        kId: this.knowledgeId
      }
    }
  • 第三版嘗試

第二版看起來沒問題,可是若是我要在某個地方改變這個data中的knowledgeId屬性,子組件是獲取不到的,怎麼解決? https://www.jianshu.com/p/ae0...,這篇文章提到了:ui

提示:provide 和 inject
綁定並非可響應的。這是刻意爲之的。然而,若是你傳入了一個可監聽的對象,那麼其對象的屬性仍是可響應的。

雖然上面講到了本質,老菜鳥都明白,小菜鳥茫然不解,因此它不能阻止我不寫下這篇文章,緣由在於它沒有提及這個可監聽對象是怎麼個回事。傳入的對象是指provide中的對象仍是data的對象?第三版改寫成在provide傳入對象this

data() {
      return {
        knowledgeId: ''
      }
    },
    provide() {
      return {
        pData: {
          kId: this.knowledgeId
        }
      }
    },
    mounted() {
      // 更改data中的knowledgeId的值
      this.knowledgeId = 2
    }
  • 第四版嘗試

第三版的寫法在子組件中是沒法獲取變動後的knowledgeId的內容,那麼就在data中包裝一個對象,可是仍是不行,第五版改寫立刻開始

data() {
      return {
        knowledge: {
          knowledgeId: ''
        }
      }
    },
    provide() {
      return {
        kId: this.knowledge.knowledgeId
      }
    },
    mounted() {
      this.knowledge.knowledgeId = 2
    }
  • 第五版嘗試

很高興的說,這版就是終結版,它能夠在子組件獲取到knowledgeId了,原理是什麼? 誰在意呢,用別人的工具,用的開心就好

data() {
      return {
        knowledge: {
          knowledgeId: ''
        }
      }
    },
    provide() {
      return {
        // 直接傳對象
        kData: this.knowledge
      }
    },
    mounted() {
      this.knowledge.knowledgeId = 2
    }

存在的小問題

正如文章:https://www.jianshu.com/p/ae0... 第三點提到的,執行順序的問題,上面在mounted中處理provide的數據有時會致使子組件獲取到的是父屬性knowledge.knowledgeId的默認屬性'',因此把provide數據生成的處理邏輯放到created裏面就能夠避免這個問題的發生

題外話

上面變動knowledgId採用了從路由獲取參數,但刷新頁面致使參數丟失,這是由於路由是:
path: 'detail'而不是path: 'detail/:knowledgeId',雖然前者經過
this.$router.push({ name: 'knowledgeDetail', params: { knowledgeId: knowledgeId } }) 也能傳,但刷新就參數丟失了,同時webstorm更改後時不時抽筋不當即更新頁面,只能手動刪除html樣式來告訴IDE更新,這些無疑加大了對provide/inject剛纔是出問題的排查難度,索性寫下這篇文章指引那些用別人工具還用這麼辛苦,寫尼瑪代碼的人找到出路

mounted() {
      this.knowledge.knowledgeId = this.$route.params.knowledgeId
    }
相關文章
相關標籤/搜索