上次學(xué)習(xí)了vue-router的使用拓劝,讓我能夠在各個(gè)頁(yè)面間切換底循,將頁(yè)面搭建了起來(lái)仿滔。這次則要學(xué)習(xí)vue的狀態(tài)管理模式——vuex惠毁。
注:本文只是個(gè)人對(duì)vuex學(xué)習(xí)的一些理解,要深刻掌握還需要認(rèn)真查閱官方文檔崎页。
一鞠绰、基本介紹
Vuex 是一個(gè)專為 Vue.js 的SPA單頁(yè)組件化應(yīng)用程序開發(fā)的狀態(tài)管理模式插件。
由于Vue SPA應(yīng)用的模塊化飒焦,每個(gè)組件都有它各自的數(shù)據(jù)(state)蜈膨、界面(view)、和方法(actions)牺荠。這些數(shù)據(jù)翁巍、界面和方法分布在各個(gè)組件中,當(dāng)項(xiàng)目?jī)?nèi)容變得越來(lái)越多時(shí)休雌,每個(gè)組件中的狀態(tài)會(huì)變得很難管理灶壶。這是vuex就派上用場(chǎng)啦~下面我們看一個(gè)簡(jiǎn)單的vuex例子。
1. 單個(gè)組件中的狀態(tài)
假如只是在單個(gè)組件中要改變界面view很簡(jiǎn)單杈曲,只需要改變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>
所以,單個(gè)組件中的原理圖是這樣的:
2. 多個(gè)組件中的狀態(tài)
然而担扑,我們作為組件化的SPA應(yīng)用洒嗤,必定會(huì)牽扯到多個(gè)組件間的通信。
比如有兩個(gè)相同的組件A和B魁亦,它們共享一個(gè)數(shù)據(jù)count渔隶,并且都有一個(gè)方法可以操作這個(gè)count,我們使用vuex來(lái)寫洁奈。
A組件和B組件的代碼(代碼相同)
<template>
<div>
{{ $store.state.count }}
<button @click="increment">increment</button>
</div>
</template>
<script>
export default {
methods: {
increment () {
this.$store.commit('increment')
}
}
}
</script>
可以看到间唉,這里的兩個(gè)increment按鈕點(diǎn)擊都會(huì)同時(shí)改變兩個(gè)count的數(shù)據(jù),因?yàn)閿?shù)據(jù)源count和方法increment都是全局的呈野。
正如下面官方原理圖所畫的印叁,我們把全局?jǐn)?shù)據(jù)源state、改變數(shù)據(jù)源的方法mutations昨悼、異步操作方法actions都放提取出來(lái)放到store中率触,實(shí)現(xiàn)全局?jǐn)?shù)據(jù)狀態(tài)單獨(dú)管理的功能。
二、安裝&配置
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實(shí)例
const store = new Vuex.Store({
// 存儲(chǔ)狀態(tài)值
state: {
...
},
// 狀態(tài)值的改變方法,操作狀態(tài)值
// 提交mutations是更改Vuex狀態(tài)的唯一方法
mutations: {
...
},
// 在store中定義getters(可以認(rèn)為是store的計(jì)算屬性)皂甘。Getters接收state作為其第一個(gè)函數(shù)
getters: {
...
},
actions: {
...
}
})
// 要改變狀態(tài)值只能通過(guò)提交mutations來(lái)完成
/* eslint-disable no-new */
new Vue({
el: '#app',
template: '<App/>',
components: { App },
// 將store實(shí)例注入到根組件下的所有子組件中
store
// 子組件通過(guò)this.$store來(lái)方位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其實(shí)可以認(rèn)為是 store 的計(jì)算屬性寸莫,用法和計(jì)算屬性差不多档冬。
定義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對(duì)state的操作
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
// 變更狀態(tài)
state.count++
}
}
})
組件通過(guò)commit提交mutations的方式來(lái)請(qǐng)求改變state
this.$store.commit('increment')
這樣的好處是我們可以跟蹤到每一次state的變化盐数,以便及時(shí)分析和解決問(wèn)題。
3.2 提交載荷(Payload)
mutations方法中是可以傳參的帚屉,具體用法如下:
mutations: {
// 提交載荷 Payload
add(state, n) {
state.count += n
}
},
this.$store.commit('add', 10)
這里只是傳了一個(gè)數(shù)字漾峡,在大多數(shù)情況下,載荷應(yīng)該是一個(gè)對(duì)象牢屋,這樣可以包含多個(gè)字段并且記錄的 mutation 會(huì)更易讀烙无。
3.3 注意
mutations方法必須是同步方法皱炉!
4. actions
4.1 基本操作
之前說(shuō)mutations方法必須只能是同步方法,為了處理異步方法多搀,actions出現(xiàn)了康铭。關(guān)于action和mutations的區(qū)別有以下幾點(diǎn):
- Action 提交的是 mutation赌髓,而不是直接變更狀態(tài)调衰。
- Action 可以包含任意異步操作拇泛。
- Action 還是得通過(guò) mutation 方法來(lái)修改state
同樣是之前的increment方法,我們分別用同步和異步的action來(lái)驗(yàn)證上面所說(shuō)的與mutations的不同之處:
actions: {
increment (context) {
context.commit('increment')
},
incrementAsync (context) {
// 延時(shí)1秒
setTimeout(() => {
context.commit('increment')
}, 1000)
}
},
不同于mutations使用commit方法悯搔,actions使用dispatch方法舌仍。
this.$store.dispatch('incrementAsync')
4.2 context
context是與 store 實(shí)例具有相同方法和屬性的對(duì)象妒貌。可以通過(guò)context.state
和context.getters
來(lái)獲取 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)集中到一個(gè)很大的對(duì)象。但是节芥,當(dāng)應(yīng)用變得很大時(shí)在刺,store 對(duì)象會(huì)變得臃腫不堪头镊。
為了解決以上問(wèn)題增炭,Vuex 允許我們將 store 分割到模塊(module)。每個(gè)模塊擁有自己的 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其實(shí)還是對(duì)于大型的SPA應(yīng)用來(lái)說(shuō)的队丝,暫時(shí)對(duì)module的應(yīng)用和理解并沒有太多欲鹏,之后會(huì)補(bǔ)上這一塊兒的內(nèi)容机久。
想要了解更多module知識(shí),請(qǐng)查閱官方module文檔
作者:VioletJack
鏈接:http://www.reibang.com/p/d6f7e11f18af
來(lái)源:簡(jiǎn)書
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán)尤误,非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。