劍走偏鋒之Vue組件通信(二)——利用provide / inject屬性構建全局狀態管理

日常咱們的全局狀態管理統統都交給Vuex來,Vuex也的確是很是好的工具,並被官方做爲指定的狀態管理器。今天給你們介紹有個新的思路進行狀態管理。可能你們對provide / inject這對api有點陌生,的確也是,日常開發中咱們基本也不會用到。vue

官方 api有這樣一句話:這對選項須要一塊兒使用,以容許一個祖先組件向其全部子孫後代注入一個依賴,不論組件層次有多深,並在起上下游關係成立的時間裏始終生效。

看圖片能夠知道,provide指望傳入一個Object,而inject能夠接受的值包括(1)一個字符串數組 (2)一個對象。代碼以下:(最簡單的寫法)api

// 父組件 App.vue
export default {
  name: 'App',
  provide: {
    parentKey: 'aaa'
  }
 }

複製代碼
// 子組件 chidlren.vue
export default {
  inject: ['parentKey'],
  created () {
    console.log(this.parentKey)
  }
}
複製代碼

在打印臺能夠看到aaa被輸出了出來,既然inject指望值是個數組,那應該也能夠這樣數組

// 父組件 App.vue
export default {
  name: 'App',
  provide: {
    parentKey: { a: 'haha' },
    parentKey2: [1, 2]
  }
 }

複製代碼
// 子組件 chidlren.vue
export default {
  inject: ['parentKey', 'parentKey2'],
  created () {
    console.log(this.parentKey, this.parentKey2)
  }
}
複製代碼

以前咱們傳遞是個字符串,發現其實傳遞什麼均可以,對應的對象和數組都打印出來了。 若是僅僅只是這樣,好像也沒什麼。看到api有這樣一句話:bash

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

咱們能夠試下:iview

// 父組件 App.vue
<template>
  <div class="app">
    <router-view></router-view>
    <button @click="changeKey"> 按鈕</button>
  </div>
</template>
export default {
provide () {
    return {
      parentKey: this.key
    }
  },
  methods: {
    changeKey () {
      this.key.push(2)
    }
  },
  data () {
    return {
      key: [1]
    }
  }
 }
複製代碼
// 子組件 chidlren.vue
export default {
  inject: ['parentKey'],
  created () {
    let afterKey = JSON.stringify(this.parentKey)
    let timer = setInterval(() => {
      console.log(this.parentKey)
      if (afterKey !== JSON.stringify(this.parentKey)) clearInterval(timer)
    }, 1000)
  }
 }
複製代碼

最後能夠看見當點擊按鈕以後,在子組件chidlren.vue中輸出的值變化了,定時器也中止了。ide

這裏面有幾個要注意的地方 (1). 這時候provide必須爲一個工廠函數,若是你是這樣寫的provide: {parentKey: this.key}也就是跟以前這種寫法,控制檯會報未定義key的錯誤 (2)不要傳字符串之類的值過去,好比:parentKey: this.key 而你在data中是這樣定義keykey: 'aaa,提示下,他並非一個可響應的數據,你可能會說,那不對啊,我在當前組件改變這個值,模板裏輸出的也會變啊。這時候其實可響應的值是this當前組件 (3)你們不要試圖替換數組來響應(爲何說這條,由於不注意我也犯了這個錯誤 :) (4)一旦注入了某個數據,好比上面示例中的 parentKey,那這個組件中就不能再聲明 parentKey 這個數據了,由於它已經被父級佔有)函數

注意:在變異 (不是替換) 對象或數組時,舊值將與新值相同,由於它們的引用指向同一個對象/數組。Vue 不會保留變異以前值的副本。(來源Vue官網)工具

好像說了這麼久,沒說到與標題相關的。:)-- 接下來久介紹下構建全局狀態管理的思路網站

// 父組件(也能夠說是根組件) App.vue
export default {
  name: 'App',
  provide () {
    return {
      app: this
    }
  },
  methods: {
    changeKey () {
      this.key.push(2)
    }
  },
  data () {
    return {
      key: [1],
      transitionName: 'slide-right'
    }
  }
}

複製代碼
// 子組件 chidlren.vue
export default {
  inject: ['app'],
  created () {
    console.log(this.app)
    console.log(this.app.key)
    this.app.changeKey()
  }
}
複製代碼

這樣你就能夠拿到根節點app全部的東西了,還能夠訪問他的方法。以此將根節點做爲狀態管理器。 若是你以爲這樣狀態多起來,十分難管理,你可使用混合mixins,將不一樣的邏輯分開到不一樣的 js 文件裏。固然這種事是仁者見仁智者見智,你可使用this.$root訪問根節點,還能夠掛載在Vue.prototype的原型上。哈哈,這些方法是否是感受有點邪門歪道的感受。因此官網有這麼一句話:

provide 和 inject 主要爲高階插件/組件庫提供用例。並不推薦直接用於應用程序代碼中。

給你們介紹下這個網站dev.iviewui.com,這個網站就是使用此方法作出來的,這樣減小了Vuex的依賴使用vue自己做爲狀態管理器,固然,若是你的網站很大,仍是建議使用Vuex

這對api還有不少東西能夠挖掘的,好比使用ES2015的Symbol做爲惟一值,inject中可使用default做爲默認值等等。用法仍是同窗們去看看官網。此次久到此爲止,清明放假了,仍是休息休息。:)

若有錯誤,歡迎指出。

相關文章
相關標籤/搜索