Vue通過provide/inject模擬實現Vuex

我們知道,在做 Vue 大型項目時,可以使用 Vuex 做狀態管理,它是一個專爲 Vue.js 開發的狀態管理模式,用於集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。但是由於Vuex的包很大,一些小型項目,組件之間的通信其實沒有必要用Vuex。

ref 和 $parent / $children不同的是,ref 和 $parent / $children主要是父子之間的通信,當組件 A 和組件 B 中間隔了數代(甚至不確定具體級別)時。以往會藉助 Vuex 或 Bus 這樣的解決方案,不得不引入三方庫來支持。這時候就就可以用provide和inject。

實現 Vuex

一般在 webpack 中使用 Vue.js,都會有一個入口文件 main.js,裏面通常導入了 Vue、VueRouter、iView 等庫,通常也會導入一個入口組件 app.vue 作爲根組件。一個簡單的 app.vue 可能只有以下代碼:

<template>
  <div>
    <router-view></router-view>
  </div>
</template>
<script>
  export default {

  }
</script>

使用 provide / inject 替代 Vuex,就是在這個 app.vue 文件上做文章。我們把 app.vue 理解爲一個最外層的根組件,用來存儲所有需要的全局數據和狀態,甚至是計算屬性(computed)、方法(methods)等。因爲你的項目中所有的組件(包含路由),它的父組件(或根組件)都是 app.vue,所以我們把整個 app.vue 實例通過 provide 對外提供。

<template>
  <div>
    <router-view></router-view>
  </div>
</template>
<script>
  export default {
    provide () {
      return {
        app: this
      }
    }
  }
</script>

上面,我們把整個 app.vue 的實例 this 對外提供,命名爲 app(這個名字可以自定義,推薦使用 app,使用這個名字後,子組件不能再使用它作爲局部屬性)。接下來,任何組件(或路由)只要通過 inject 注入 app.vue 的 app 的話,都可以直接通過 this.app.xxx 來訪問 app.vue 的 data、computed、methods 等內容。

app.vue 是整個項目第一個被渲染的組件,而且只會渲染一次(即使切換路由,app.vue 也不會被再次渲染),利用這個特性,很適合做一次性全局的狀態數據管理,例如,我們將用戶的登錄信息保存起來。

<script>
  export default {
    provide () {
      return {
        app: this
      }
    },
    data () {
      return {
        userInfo: null
      }
    },
    methods: {
      getUserInfo () {
        // 這裏通過 ajax 獲取用戶信息後,賦值給 this.userInfo,以下爲僞代碼
        $.ajax('/user/info', (data) => {
          this.userInfo = data;
        });
      }
    },
    mounted () {
      this.getUserInfo();
    }
  }
</script>

這樣,任何頁面或組件,只要通過 inject 注入 app 後,就可以直接訪問 userInfo 的數據了。

除了直接使用數據,還可以調用方法。比如在某個頁面裏,修改了個人資料,這時一開始在 app.vue 裏獲取的 userInfo 已經不是最新的了,需要重新獲取。可以這樣使用:

<template>
  <div>
    {{ app.userInfo }}
  </div>
</template>
<script>
  export default {
    inject: ['app'],
    methods: {
      changeUserInfo () {
        // 這裏修改完用戶數據後,通知 app.vue 更新,以下爲僞代碼
        $.ajax('/user/update', () => {
          // 直接通過 this.app 就可以調用 app.vue 裏的方法
          this.app.getUserInfo();
        })
      }
    }
  }
</script>

不過需要注意的是:provide 和 inject 主要在開發高階插件/組件庫時使用。並不推薦用於普通應用程序代碼中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章