Vuex 講解
一、前言

在 Vue 項(xiàng)目中,如果項(xiàng)目結(jié)構(gòu)簡(jiǎn)單,父子組件之間的數(shù)據(jù)傳遞可以使用 props 或者 $emit 等方式 (詳參博文《Vue進(jìn)階(六):組件之間的數(shù)據(jù)傳遞》)。如果是大型項(xiàng)目,很多時(shí)候都需要在子組件之間傳遞數(shù)據(jù),使用之前的方式就不太方便。Vue 的狀態(tài)管理工具 Vuex完美的解決了這個(gè)問題。
二、什么是Vuex? 為什么要使用Vuex ?
首先,我們需要知道 vue 是以單向數(shù)據(jù)流的方式驅(qū)動(dòng)的。具有以下特點(diǎn):
多個(gè)視圖依賴于同一狀態(tài)。
來自不同視圖的行為需要變更同一狀態(tài)。
vuex 類似Redux的狀態(tài)管理器, 用來管理Vue的所有組件狀態(tài),采用集中式存儲(chǔ)管理應(yīng)用的所有組件狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測(cè)的方式發(fā)生變化。
狀態(tài)機(jī)就是保存你的狀態(tài)和狀態(tài)變化的一個(gè)盒子。這里有一些不同種類的狀態(tài)機(jī),適用于我們這個(gè)案例的是有限狀態(tài)機(jī)。像它的名字一樣,有限狀態(tài)機(jī)包含有限的幾種狀態(tài)。它接收一個(gè)輸入并且基于這個(gè)輸入和當(dāng)前的狀態(tài)決定下一個(gè)狀態(tài),可能會(huì)有多種情況輸出。當(dāng)狀態(tài)機(jī)改變了狀態(tài),我們就稱為它過渡到一個(gè)新的狀態(tài)
每一個(gè) Vuex 應(yīng)用的核心就是 store(倉(cāng)庫(kù))。store基本上就是一個(gè)容器,它包含應(yīng)用中大部分的狀態(tài) (state)。Vuex 和單純的全局對(duì)象有以下兩點(diǎn)不同:
Vuex 的狀態(tài)存儲(chǔ)是響應(yīng)式的。當(dāng) Vue 組件從 store 中讀取狀態(tài)的時(shí)候,若 store 中的狀態(tài)發(fā)生變化,那么相應(yīng)的組件也會(huì)相應(yīng)地得到高效更新。
不能直接改變 store 中的狀態(tài)。改變 store 中數(shù)據(jù)狀態(tài)的唯一途徑就是顯式地提交 (commit) mutation。
這樣使得我們可以方便地跟蹤每一個(gè)狀態(tài)的變化,從而讓我們能夠?qū)崿F(xiàn)一些工具幫助我們更好地了解我們的應(yīng)用。
三、安裝并引入 Vuex
項(xiàng)目結(jié)構(gòu)如下:
注:當(dāng)應(yīng)用變得比較復(fù)雜時(shí)候,store對(duì)象有可能變的相當(dāng)臃腫。在此情況下,vuex允許將store分割成模塊(module),每個(gè)模塊有自己的state,mutation,action,getter甚至是嵌套子模塊等。
首先使用 npm 安裝 Vuex。
cnpm install vuex -S
然后在main.js中 引入store.js, 然后注入 store。
import Vue from 'vue' import App from './App' import Vuex from 'vuex' import store from './vuex/store' // 讓vue使用vuex工具來實(shí)現(xiàn)組件之間的數(shù)據(jù)共享 Vue.use(Vuex) /* eslint-disable no-new */ new Vue({ el: '#app', // 注入 store store, render: h => h(App) })
四、構(gòu)建核心倉(cāng)庫(kù) store.js
Vuex 應(yīng)用的狀態(tài) state 都應(yīng)當(dāng)存放在 store.js 里面,Vue 組件可以從 store.js 里面獲取狀態(tài),可以把 store 通俗的理解為一個(gè)全局變量的倉(cāng)庫(kù)。
但是和單純的全局變量又有一些區(qū)別,主要體現(xiàn)在當(dāng) store 中的狀態(tài)發(fā)生改變時(shí),相應(yīng)的 vue 組件也會(huì)得到高效更新。
在 src 目錄下創(chuàng)建一個(gè) vuex 目錄,將 store.js 放到 vuex 目錄下。
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const store = new Vuex.Store({ // 定義狀態(tài),存儲(chǔ)數(shù)據(jù)的對(duì)象,我們可以將你需要存儲(chǔ)的數(shù)據(jù)在這個(gè)state中定義 state: { author: 'Wise Wrong' } }) export default store
這是一個(gè)最簡(jiǎn)單的 store.js,里面只存放一個(gè)狀態(tài) author。
注:雖然在 main.js 中已經(jīng)引入了 Vue 和 Vuex,但是這里還得再引入一次.
五、將狀態(tài)映射到組件
這是 footer.vue 的 html 和 script 部分。
在 computed 中,將 this.$store.state.author 的值返回給 html 中的 author。頁(yè)面渲染之后,就能獲取到 author 的值。
六、在組件中修改狀態(tài)
然后在 header.vue 中添加一個(gè)輸入框,將輸入框的值傳給 store.js 中的 author,這里使用 Element-UI 作為樣式框架。
上面將輸入框 input 的值綁定為 inputTxt,然后在后面的按鈕 button 上綁定 click 事件,觸發(fā) setAuthor 方法。
methods: { setAuthor: function () { this.$store.state.author = this.inpuTxt } }
在 setAuthor 方法中,將輸入框的值 inputTxt 賦給 Vuex 中的狀態(tài) author,從而實(shí)現(xiàn)子組件之間的數(shù)據(jù)傳遞。
七、官方推薦的修改狀態(tài)的方式
上面的示例是在 setAuthor 直接使用賦值的方式修改狀態(tài) author,但是 vue 官方推薦使用下面的方法:
首先在 store.js 中定義一個(gè)方法 newAuthor,其中第一個(gè)參數(shù) state 就是 $store.state,第二個(gè)參數(shù) msg 需要另外傳入,然后修改 header.vue 中的 setAuthor 方法。
這里使用 $store.commit 調(diào)用mutations中定義的函數(shù) newAuthor,這個(gè)函數(shù)就是操作state中定義的成員函數(shù),并將 this.inputTxt 傳給 msg,從而修改 author。
禁止直接改變 store 中的狀態(tài)!
改變 store 中數(shù)據(jù)狀態(tài)的唯一途徑就是顯式地提交 (commit) mutation(this.$store.commit(‘mutations方法名’,值))。這樣顯式地提交(commit) mutations,可以讓我們更好的跟蹤每一個(gè)狀態(tài)的變化,所以在大型項(xiàng)目中,更推薦使用第二種方法。
// 存儲(chǔ)數(shù)據(jù)的對(duì)象,可以將需要存儲(chǔ)的數(shù)據(jù)在這個(gè)state中定義 const state = { // 當(dāng)前登陸的用戶名 username: '' } const mutations = { // 提供一個(gè)方法,為state中的username賦值 // 這些方法有一個(gè)默認(rèn)的參數(shù),這個(gè)參數(shù)就是當(dāng)前store中的State setUserName (state, username) { //存入一個(gè)值 state.username = username localStorage.setItem('myname', username) }, getUserName (state) { //輸出一個(gè)值 return state.username } } //使用的時(shí)候---> 通過commit調(diào)用mutations中定義的函數(shù),這個(gè)函數(shù)就是操作state中定義的成員的函數(shù) // this.$store.commit('setUserName', res.data.username(請(qǐng)求返回的值)) const actions = { setUserNameAction: ({commit}, username) => { commit('setUserName', username) }, getUserNameAction: ({commit}) => { commit('getUserName') } } // 通過action來觸發(fā)mutations中的函數(shù),這種觸發(fā)方式是異步方式 //存入 this.$store.dispatch('setUserNameAction', res.data.username + 'aa') //取出 this.currentUserName = this.$store.dispatch('getUserNameAction') // Getters是從 store 中的 state 中派生出一些狀態(tài),即當(dāng)出現(xiàn)多處需要導(dǎo)入某個(gè)狀態(tài)時(shí),結(jié)果不是很理想,所以getters的返回值會(huì)根據(jù)它的依賴被緩存起來,且只有當(dāng)它的依賴值發(fā)生了改變才會(huì)被重新計(jì)算。 const getters = { getUserName: (state) => { return localStorage.getItem('myname') } } //使用的時(shí)候,直接使用 // 你好:{{$store.getters.getUserName}}
八、拓展閱讀
《Vue進(jìn)階(四):使用 Vuex + axios 發(fā)送請(qǐng)求》
《Vue進(jìn)階(七十三):vuex中store存儲(chǔ)store.commit和store.dispatch的區(qū)別及用法》
《Vue進(jìn)階(四十三):Vuex之Mutations詳解》
《Vue進(jìn)階(幺肆捌):Vuex輔助函數(shù)詳解》
《Vue進(jìn)階(二十七):Vuex之getters,mapGetters,…mapGetters詳解》
Vue 容器
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。