在 學習vue 開發中,組件通訊一直是一大痛點。
當項目是很簡單的 SPA 或者多入口項目時,能夠靠着 vue 自帶的 prop/$emit 進行組件通訊;規模再大一些,能夠搭配使用 bus 總線進行兄弟組件通訊;項目再大一些,出現更復雜的組件關係時,複雜的組件通訊可讓你寫得懷疑人生。
萬幸的是, vue 官方出品了 vuex ,經過全局式的狀態管理,解決了這一痛點。
雖然 vuex 很好用,可是,不少小夥伴和我吐槽 vuex 的文檔和 vue-ssr 的文檔同樣,讓人看得一臉懵逼。vue
正常狀況下,咱們使用 vue-cli3 生成項目時,能夠選擇集成 vuex 到項目中。此時, vue-cli3 會自動安裝 vuex ,並在 src 文件夾下生成 store.js 完成 vuex 的引入和配置。
可是,不少同窗並無使用 vue-cli3 或者生成項目時沒有選擇集成 vuex 。此時,就只能手動安裝並引入 vuex 了。vuex
因爲 vuex 是用於全局狀態管理的,因此,它不只僅做用於開發環境,並且還要用於生產環境。
顯而易見,安裝 vuex 應該使用 -S 即 --save 命令。npm install vuex -S
vue-cli
相似於 vue-cli3 生成的項目,咱們在 src 文件夾下新建 store.js ,並在其中寫入:npm
// store.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({})
而後,咱們只須要在 vue 實例中引入 store.js 中的 Vuex.Store 實例便可:app
// main.js import Vue from 'vue' import App from './App.vue' import router from './router' import store from './store' Vue.config.productionTip = false new Vue({ router, // 引入store store, render: h => h(App) }).$mount('#app')
完成了 vuex 的安裝和引入,接下來咱們進入 Vuex 的使用。
vuex 中有三要素: state, mutation 以及 action 。它們之間的關係能夠用官網那張著名的圖來表示:異步
簡單來講, state 表示狀態,相似於 vue 中的 data (其實本質上就是差很少的, vuex 在 vue 的 beforeCreate 鉤子中將 state 混入進 data)。可是,它們又有很大的不一樣: 在使用者看來, state 是全局的,這得益於 vuex 的設計理念——單一狀態樹。這些我將在後幾篇文章中詳細,如今咱們只須要知道 state 是相似於全局下的 data 。
接下來咱們經過一個簡單例子來感覺下 state :
首先,咱們須要修改 store.js 文件,配置 state 。能夠看到,咱們在生成 Vuex.Store 實例時傳入了實例化選項對象,對象包含一個 state 屬性, state 對象的屬性就是咱們定義的全局狀態。
此時,咱們定義了一個全局狀態——count ,並將其的初始值設爲1。工具
// store.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ // 添加state state: { count: 1 } })
接下來,咱們須要在組件中引用 count,因爲它是全局狀態,咱們能夠在任何一個組件中使用。爲了展現其威力,咱們在兩個不一樣的組件中使用它。
首先咱們在 App.vue 中使用它:
在模板中,咱們使用 $store.state.count 引入該全局狀態,沒錯,使用它就是那麼簡單,只須要 以 $store.state.key 的形式調用。學習
// App.vue <template> <div id="app"> <div id="nav"> {{$store.state.count}} <router-link to="/">Home</router-link> | <router-link to="/about">About</router-link> </div> <router-view/> </div> </template>
能夠發現, Home 前多出了一個 1 ,這表明着咱們成功引入了全局狀態 count 。
接下來咱們在 Home.vue 的子組件 HelloWorld.vue 中引入 count 。
相同的引用方式: $store.state.count優化
// HelloWorld.vue <template> <div class="hello"> {{$store.state.count}} </div> </template>
能夠發現,success。網站
可是,上面的示例有個問題,那就是全局狀態是靜態的。若是在實際應用場景中,通常來講,會常常更改狀態。
有的同窗會說,咱們直接在方法中修改 this.$store.state.key 的值不就好了嗎?
很差意思,固然是不行的。
state 和 data 的另外一大區別在於,你不能直接改變 state 。改變 store 中的狀態的惟一途徑就是顯式地提交 (commit) mutation。這樣使得咱們能夠方便地跟蹤每個狀態的變化,從而讓咱們可以實現一些工具幫助咱們更好地瞭解咱們的應用。
簡而言之,咱們把 mutation 當作接收 state 做爲參數並修改 state 的自定義事件便可,上一段所說的 commit 就是觸發 mutaion 這個自定義事件的方法。
光說不練假把式,接下來,咱們對爲 vuex 添加上 mutation ,實現 state 的動態改變:
首先,固然是修改生成 Vuex.Store 示例的選項對象,爲其添加 mutations 。
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { count: 1 }, // 添加mutation mutations: { increment (state) { state.count++ } } })
在上面的代碼中,咱們添加了一個名爲 increment 的 mutation 。完成了自定義事件,接下來,咱們只須要在組件中對 mutation 進行觸發便可。
咱們在 HelloWorld.vue 添加一個按鈕,每次點擊觸發一次 increment 這個 mutation 。能夠發現,觸發方式很簡單,只須要調用 store 自帶的 commit 方法,其中參數爲須要觸發的 mutation 的名稱。
// HelloWorld.vue <template> <div class="hello"> <div>{{$store.state.count}}</div> <button @click="$store.commit('increment')">修改count</button> </div> </template>
點擊頁面中的按鈕,你會發現,頁面中的兩個 count 都同時增長了1,說明咱們成功實現了 state 的動態修改。
action 相似於 mutation ,也至關於一種自定義事件。只不過, action 操做的是 mutation 而不是 state 。
添加 action 的方法相似,在選項對象中新增 action 屬性便可。與 mutation 的參數不一樣, action 的參數就是當前建立的 Vue.store 對象實例的上下文,通常將其命名爲 context 。咱們須要使用其自帶的 commit 方法來觸發 mutation 。
下面我經過實際的例子來嘗試下 action :
首先,修改選項對象,使得新添加的 action 能夠觸發以前的 mutation :
// store.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { count: 1 }, mutations: { increment (state) { state.count++ } }, actions: { increment ({ commit }) { commit('increment') } } })
因爲咱們通常來講僅僅須要 context 中的 commit 方法,因此能夠採用解構的方式,直接調用 commit 方法,而不須要以 context.commit 的方式使用它。
接下來,只須要修改 HelloWorld.vue ,使其可以在點擊按鈕時觸發便可。
action 的觸發方式和 mutation 相似,只不過調用的方法是 dispatch 。
// HelloWorld.vue <template> <div class="hello"> <div>{{$store.state.count}}</div> <button @click="$store.dispatch('increment')">修改count</button> </div> </template>
點擊頁面按鈕,你會發現,實現了和以前相同的效果。
學會了 vuex 三jian客: state , mutation , action ,咱們再回過頭看看前面的那張關係圖,此時應該很容易理解了吧?
組件交互觸發 action , 在 action 中進行異步操做(可選)並觸發 mutation , mutation 控制 state 的變更, state 修改以後,觸發響應式,從新渲染組件。
PS(其餘的進階用法,如: getter , module , 簡寫以及 vuex 項目結構優化,甚至 vuex 源碼解析將會在以後的文章一一講解)