上次學(xué)習(xí)了vue-router的使用,讓我能夠在各個頁面間切換,將頁面搭建了起來。這次則要學(xué)習(xí)vue的狀態(tài)管理模式——vuex。
注:本文只是個人對vuex學(xué)習(xí)的一些理解,要深刻掌握還需要認(rèn)真查閱官方文檔。
一、基本介紹
Vuex 是一個專為 Vue.js 的SPA單頁組件化應(yīng)用程序開發(fā)的狀態(tài)管理模式插件。
由于Vue SPA應(yīng)用的模塊化,每個組件都有它各自的數(shù)據(jù)(state)、界面(view)、和方法(actions)。這些數(shù)據(jù)、界面和方法分布在各個組件中,當(dāng)項目內(nèi)容變得越來越多時,每個組件中的狀態(tài)會變得很難管理。這是vuex就派上用場啦~下面我們看一個簡單的vuex例子。
1. 單個組件中的狀態(tài)
假如只是在單個組件中要改變界面view很簡單,只需要改變state數(shù)據(jù)源即可。如下代碼:
<template>
<div>
view: {{ count }}
<button @click="increment">increment</button>
</div>
</template>
<script>
export default {
// state
data () {
return {
count: 0
}
},
// actions
methods: {
increment () {
this.count++
}
}
}
</script>
所以,單個組件中的原理圖是這樣的:

2. 多個組件中的狀態(tài)
然而,我們作為組件化的SPA應(yīng)用,必定會牽扯到多個組件間的通信。
比如有兩個相同的組件A和B,它們共享一個數(shù)據(jù)count,并且都有一個方法可以操作這個count,我們使用vuex來寫。
A組件和B組件的代碼(代碼相同)
<template>
<div>
{{ $store.state.count }}
<button @click="increment">increment</button>
</div>
</template>
<script>
export default {
methods: {
increment () {
this.$store.commit('increment')
}
}
}
</script>


可以看到,這里的兩個increment按鈕點擊都會同時改變兩個count的數(shù)據(jù),因為數(shù)據(jù)源count和方法increment都是全局的。
正如下面官方原理圖所畫的,我們把全局?jǐn)?shù)據(jù)源state、改變數(shù)據(jù)源的方法mutations、異步操作方法actions都放提取出來放到store中,實現(xiàn)全局?jǐn)?shù)據(jù)狀態(tài)單獨管理的功能。

二、安裝&配置
1. 安裝vuex
使用npm安裝并保存到package.json中:
npm install vuex --save
package.json
"devDependencies": {
...
"vuex": "^2.1.1",
...
},
2. 配置
配置方式和路由的配置方式差不多
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
//創(chuàng)建Store實例
const store = new Vuex.Store({
// 存儲狀態(tài)值
state: {
...
},
// 狀態(tài)值的改變方法,操作狀態(tài)值
// 提交mutations是更改Vuex狀態(tài)的唯一方法
mutations: {
...
},
// 在store中定義getters(可以認(rèn)為是store的計算屬性)。Getters接收state作為其第一個函數(shù)
getters: {
...
},
actions: {
...
}
})
// 要改變狀態(tài)值只能通過提交mutations來完成
/* eslint-disable no-new */
new Vue({
el: '#app',
template: '<App/>',
components: { App },
// 將store實例注入到根組件下的所有子組件中
store
// 子組件通過this.$store來方位store
})
三、核心概念
1. state
state就是全局的狀態(tài)(數(shù)據(jù)源),我們可以用以下方式在Vue 組件中獲得Vuex的state狀態(tài)
template
<div>
{{ $store.state.count }}
</div>
script
console.log(this.$store.state.count)
2. getters
getters其實可以認(rèn)為是 store 的計算屬性,用法和計算屬性差不多。
定義getter:
getters: {
done(state) {
return state.count + 5;
},
}
使用getter
console.log(this.$store.getters.done)
3. mutations
mutations是操作state的唯一方法,即只有mutations方法能夠改變state狀態(tài)值。
3.1 基本操作
mutations對state的操作
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
// 變更狀態(tài)
state.count++
}
}
})
組件通過commit提交mutations的方式來請求改變state
this.$store.commit('increment')
這樣的好處是我們可以跟蹤到每一次state的變化,以便及時分析和解決問題。
3.2 提交載荷(Payload)
mutations方法中是可以傳參的,具體用法如下:
mutations: {
// 提交載荷 Payload
add(state, n) {
state.count += n
}
},
this.$store.commit('add', 10)
這里只是傳了一個數(shù)字,在大多數(shù)情況下,載荷應(yīng)該是一個對象,這樣可以包含多個字段并且記錄的 mutation 會更易讀。
3.3 注意
mutations方法必須是同步方法!
4. actions
4.1 基本操作
之前說mutations方法必須只能是同步方法,為了處理異步方法,actions出現(xiàn)了。關(guān)于action和mutations的區(qū)別有以下幾點:
- Action 提交的是 mutation,而不是直接變更狀態(tài)。
- Action 可以包含任意異步操作。
- Action 還是得通過 mutation 方法來修改state
同樣是之前的increment方法,我們分別用同步和異步的action來驗證上面所說的與mutations的不同之處:
actions: {
increment (context) {
context.commit('increment')
},
incrementAsync (context) {
// 延時1秒
setTimeout(() => {
context.commit('increment')
}, 1000)
}
},
不同于mutations使用commit方法,actions使用dispatch方法。
this.$store.dispatch('incrementAsync')
4.2 context
context是與 store 實例具有相同方法和屬性的對象。可以通過context.state和context.getters來獲取 state 和 getters。
4.3 以載荷形式分發(fā)
incrementAsyncWithValue (context, value) {
setTimeout(() => {
context.commit('add', value)
}, 1000)
}
this.$store.dispatch('incrementAsyncWithValue', 5)
5. module
使用單一狀態(tài)樹,導(dǎo)致應(yīng)用的所有狀態(tài)集中到一個很大的對象。但是,當(dāng)應(yīng)用變得很大時,store 對象會變得臃腫不堪。
為了解決以上問題,Vuex 允許我們將 store 分割到模塊(module)。每個模塊擁有自己的 state、mutation、action、getters、甚至是嵌套子模塊——從上至下進(jìn)行類似的分割:
const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的狀態(tài)
store.state.b // -> moduleB 的狀態(tài)
module其實還是對于大型的SPA應(yīng)用來說的,暫時對module的應(yīng)用和理解并沒有太多,之后會補(bǔ)上這一塊兒的內(nèi)容。
想要了解更多module知識,請查閱官方module文檔
Vue.js學(xué)習(xí)系列
鑒于前端知識碎片化嚴(yán)重,我希望能夠系統(tǒng)化的整理出一套關(guān)于Vue的學(xué)習(xí)系列博客。
Vue.js學(xué)習(xí)系列一 —— vue-router2學(xué)習(xí)實踐筆記(附DEMO)
Vue.js學(xué)習(xí)系列二 —— vuex學(xué)習(xí)實踐筆記(附DEMO)
Vue.js學(xué)習(xí)系列三 —— axios和網(wǎng)絡(luò)傳輸相關(guān)知識的學(xué)習(xí)實踐
Vue.js學(xué)習(xí)系列四 —— Webpack打包工具的使用
Vue.js學(xué)習(xí)系列五 —— 從VUE-CLI來聊聊ESLint
Vue.js學(xué)習(xí)系列六 —— Vue單元測試Karma+Mocha學(xué)習(xí)筆記
Vue.js學(xué)習(xí)系列七 —— Vue服務(wù)器渲染Nuxt學(xué)習(xí)
Vue.js學(xué)習(xí)系列八 —— Vue源碼學(xué)習(xí)之State學(xué)習(xí)
Vue.js學(xué)習(xí)系列項目地址
本文源碼已收入到GitHub中,以供參考,當(dāng)然能留下一個star更好啦-。
https://github.com/violetjack/VueStudyDemos
關(guān)于作者
VioletJack,高效學(xué)習(xí)前端工程師,喜歡研究提高效率的方法,也專注于Vue前端相關(guān)知識的學(xué)習(xí)、整理。
歡迎關(guān)注、點贊、評論留言~我將持續(xù)產(chǎn)出Vue相關(guān)優(yōu)質(zhì)內(nèi)容。
新浪微博: http://weibo.com/u/2640909603
掘金:https://gold.xitu.io/user/571d953d39b0570068145cd1
CSDN: http://blog.csdn.net/violetjack0808
簡書: http://www.itdecent.cn/users/54ae4af3a98d/latest_articles
Github: https://github.com/violetjack
打個廣告
鏈家上海研發(fā)中心招聘前端、后端、測試。
機(jī)會不多,需要內(nèi)推機(jī)會的請將簡歷發(fā)送至 dingxiaojie001@ke.com。