Vue的Flux框架之Vuex狀態(tài)管理器
學(xué)習(xí)vue之前,最重要是弄懂兩個(gè)概念,一是“what”,要理解vuex是什么;二是“why”,要清楚為什么要用vuex。
Vuex是什么?
Vuex 類(lèi)似 React 里面的 Redux 的狀態(tài)管理器,用來(lái)管理Vue的所有組件狀態(tài)。
為什么使用Vuex?
當(dāng)你打算開(kāi)發(fā)大型單頁(yè)應(yīng)用(SPA),會(huì)出現(xiàn)多個(gè)視圖組件依賴(lài)同一個(gè)狀態(tài),來(lái)自不同視圖的行為需要變更同一個(gè)狀態(tài)。
遇到以上情況時(shí)候,你就應(yīng)該考慮使用Vuex了,它能把組件的共享狀態(tài)抽取出來(lái),當(dāng)做一個(gè)全局單例模式進(jìn)行管理。這樣不管你在何處改變狀態(tài),都會(huì)通知使用該狀態(tài)的組件做出相應(yīng)修改。
下面講解如何使用Vuex
一個(gè)簡(jiǎn)單的Vuex示例
本文就講解安裝Vuex,直接通過(guò)代碼講解Vuex使用。
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
})
上面就是一個(gè)簡(jiǎn)單的Vuex示例,每一個(gè)Vuex應(yīng)用就是一個(gè)store,在store中包含組件中的共享狀態(tài)state和改變狀態(tài)的方法(暫且稱(chēng)作方法)mutations。
需要注意的是只能通過(guò)mutations改變store的state的狀態(tài),不能通過(guò)store.state.count = 5;直接更改(其實(shí)可以更改,不建議這么做,不通過(guò)mutations改變state,狀態(tài)不會(huì)被同步)。
使用store.commit方法觸發(fā)mutations改變state:
store.commit('increment');
console.log(store.state.count) // 1
一個(gè)簡(jiǎn)簡(jiǎn)單單的Vuex應(yīng)用就實(shí)現(xiàn)了。
在Vue組件使用Vuex
如果希望Vuex狀態(tài)更新的時(shí)候,組件數(shù)據(jù)得到相應(yīng)的更新,那么可以用計(jì)算屬性computed獲取state的更新?tīng)顟B(tài)。
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return store.state.count;
}
}
}
每一個(gè)store.state都是全局狀態(tài),在使用Vuex時(shí)候需要在根組件或(入口文件)注入。
// 根組件
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const app = new Vue({
el: '#app',
store,
components: {
Counter
},
template: `
<div class="app">
<counter></counter>
</div>
`
})
通過(guò)這種注入機(jī)制,就能在子組件Counter通過(guò)this.$store訪(fǎng)問(wèn):
// Counter 組件
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return this.$store.state.count
}
}
}
mapState函數(shù)
computed: {
count () {
return this.$store.state.count
}
}
上面通過(guò)count計(jì)算屬性獲取同名state.count屬性,如何每一次獲取都要寫(xiě)一個(gè)這樣的方法,是不顯得重復(fù)又麻煩?可以使用mapState函數(shù)簡(jiǎn)化這個(gè)過(guò)程。
import { mapState } from 'vuex';
export default {
computed: mapState ({
count: state => state.count,
countAlias: 'count', // 別名 `count` 等價(jià)于 state => state.count
})
}
還有更簡(jiǎn)單的使用方法:
computed: mapState([ 'count' // 映射 this.count 為 store.state.count ])
Getters對(duì)象
如果我們需要對(duì)state對(duì)象進(jìn)行做處理計(jì)算,如下:
computed: {
doneTodosCount () {
return this.$store.state.todos.filter(todo => todo.done).length
}
}
如果多個(gè)組件都要進(jìn)行這樣的處理,那么就要在多個(gè)組件中復(fù)制該函數(shù)。這樣是很沒(méi)有效率的事情,當(dāng)這個(gè)處理過(guò)程更改了,還有在多個(gè)組件中進(jìn)行同樣的更改,這就更加不易于維護(hù)。
Vuex中g(shù)etters對(duì)象,可以方便我們?cè)趕tore中做集中的處理。Getters接受state作為第一個(gè)參數(shù):
const store = new Vuex.Store({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done)
}
}
})
在Vue中通過(guò)store.getters對(duì)象調(diào)用:
computed: {
doneTodos () {
return this.$store.getters.doneTodos
}
}
Getter也可以接受其他getters作為第二個(gè)參數(shù):
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done)
},
doneTodosCount: (state, getters) => {
return getters.doneTodos.length
}
}
mapGetters輔助函數(shù)
與mapState類(lèi)似,都能達(dá)到簡(jiǎn)化代碼的效果。mapGetters輔助函數(shù)僅僅是將store中的getters映射到局部計(jì)算屬性:
import { mapGetters } from 'vuex'
export default {
// ...
computed: {
// 使用對(duì)象展開(kāi)運(yùn)算符將 getters 混入 computed 對(duì)象中
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}
上面也可以寫(xiě)作:
computed: mapGetters([ 'doneTodosCount', 'anotherGetter', // ... ])
所以在Vue的computed計(jì)算屬性中會(huì)存在兩種輔助函數(shù):
import { mapState, mapGetters } from 'vuex';
export default {
// ...
computed: {
...mapGetters([ ... ]),
...mapState([ ... ])
}
}
Mutations
之前也說(shuō)過(guò)了,更改Vuex的store中的狀態(tài)的唯一方法就是mutations。
每一個(gè)mutation都有一個(gè)事件類(lèi)型type和一個(gè)回調(diào)函數(shù)handler。
調(diào)用mutation,需要通過(guò)store.commit方法調(diào)用mutation type:
store.commit('increment')
Payload 提交載荷
也可以向store.commit傳入第二參數(shù),也就是mutation的payload:
mutaion: {
increment (state, n) {
state.count += n;
}
}
store.commit('increment', 10);
單單傳入一個(gè)n,可能并不能滿(mǎn)足我們的業(yè)務(wù)需要,這時(shí)候我們可以選擇傳入一個(gè)payload對(duì)象:
mutation: {
increment (state, payload) {
state.totalPrice += payload.price + payload.count;
}
}
store.commit({
type: 'increment',
price: 10,
count: 8
})
mapMutations函數(shù)
不例外,mutations也有映射函數(shù)mapMutations,幫助我們簡(jiǎn)化代碼,使用mapMutations輔助函數(shù)將組件中的methods映射為store.commit調(diào)用。
import { mapMutations } from 'vuex'
export default {
// ...
methods: {
...mapMutations([
'increment' // 映射 this.increment() 為 this.$store.commit('increment')
]),
...mapMutations({
add: 'increment' // 映射 this.add() 為 this.$store.commit('increment')
})
}
}
Actions
注 Mutations必須是同步函數(shù)。
如果我們需要異步操作和提交多個(gè)Mutations,Mutations就不能滿(mǎn)足我們需求了,這時(shí)候我們就需要Actions了。
Actions
Action 類(lèi)似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接變更狀態(tài)。
- Action 可以包含任意異步操作。
讓我們來(lái)注冊(cè)一個(gè)簡(jiǎn)單的 action:
var store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment: function(state) {
state.count++;
}
},
actions: {
increment: function(store) {
store.commit('increment');
}
}
});
分發(fā) Action
Action 函數(shù)接受一個(gè)與 store 實(shí)例具有相同方法和屬性的 context 對(duì)象,因此你可以調(diào)用 context.commit 提交一個(gè) mutation,或者通過(guò) context.state 和 context.getters 來(lái)獲取 state 和 getters。
分發(fā) Action
Action 通過(guò) store.dispatch 方法觸發(fā):
乍一眼看上去感覺(jué)多此一舉,我們直接分發(fā) mutation 豈不更方便?實(shí)際上并非如此,還記得 mutation必須同步執(zhí)行這個(gè)限制么?Action就不受約束! 我們可以在 action 內(nèi)部執(zhí)行異步操作:
actions: {
incrementAsync ({ commit }) {
setTimeout(() => {
commit('increment')
}, 1000)
}
}
Actions 支持同樣的載荷方式和對(duì)象方式進(jìn)行分發(fā):
// 以載荷形式分發(fā)
store.dispatch('incrementAsync', {
amount: 10
})
// 以對(duì)象形式分發(fā)
store.dispatch({
type: 'incrementAsync',
amount: 10
})
mapActions
同樣地,action也有相對(duì)應(yīng)的mapActions 輔助函數(shù)
mapActions
mapActions 輔助函數(shù)跟mapMutations一樣都是組件的 methods 調(diào)用:
import { mapActions } from 'vuex'
export default {
// ...
methods: {
...mapActions([
'increment' // 映射 this.increment() 為 this.$store.dispatch('increment')
]),
...mapActions({
add: 'increment' // 映射 this.add() 為 this.$store.dispatch('increment')
})
}
}
mutation-types
關(guān)于mutation-types方面的講解官方文檔很少說(shuō)明,但在實(shí)際的中大項(xiàng)目中,對(duì)==mutation-types==的配置是必不可少的,Vuex的文檔只講解了state,getters,mutation,actions四個(gè)核心概念,下面我簡(jiǎn)單補(bǔ)充下mutation-types的使用。
顧名思義,==mutation-types==其實(shí)就是mutation實(shí)例中各個(gè)方法的設(shè)定,一般要mutation方法前先在mutation-types用大寫(xiě)寫(xiě)法設(shè)定,再在mutation里引入使用,下面看看項(xiàng)目實(shí)際使用:
項(xiàng)目組織結(jié)構(gòu)

在mutation-types定義好mutation的方法結(jié)構(gòu):
//SET_SINGER,SET_SONG 為mutation中要使用的方法名 export const SET_SINGER = 'SET_SINGER' export const SET_SONG = 'SET_SONG'
在mutation中導(dǎo)入使用:
import * as types from ',/mutation-types.js'
const mutations = {
[types.SET_SINGER](state, singer) {
....
},
[types.SET_SONG](state, song) {
....
}
}
結(jié)語(yǔ)
看完上面對(duì)vuex的講解相信你已經(jīng)入門(mén)了,現(xiàn)在可以看看具體的項(xiàng)目加深理解,可以參考我的github一個(gè)購(gòu)物車(chē)?yán)? https://github.com/osjj/vue-shopCart
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Vue3嵌套路由中使用keep-alive緩存多層的實(shí)現(xiàn)
本文介紹了Vue3 嵌套路由中使用?keep-alive緩存多層的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
解決element-ui里的下拉多選框 el-select 時(shí),默認(rèn)值不可刪除問(wèn)題
這篇文章主要介紹了解決element-ui里的下拉多選框 el-select 時(shí),默認(rèn)值不可刪除問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08
vue分頁(yè)組件table-pagebar使用實(shí)例解析
這篇文章主要為大家詳細(xì)解析了vue分頁(yè)組件table-pagebar使用實(shí)例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-08-08
關(guān)于Vue3過(guò)渡動(dòng)畫(huà)的踩坑記錄
在開(kāi)發(fā)中我們想要給一個(gè)組件的顯示和消失添加某種過(guò)渡動(dòng)畫(huà),可以很好的增加用戶(hù)體驗(yàn),下面這篇文章主要給大家介紹了關(guān)于Vue3過(guò)渡動(dòng)畫(huà)踩坑的相關(guān)資料,需要的朋友可以參考下2021-12-12
vue實(shí)現(xiàn)簡(jiǎn)單學(xué)生信息管理
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)簡(jiǎn)單學(xué)生信息管理,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05
vue?頂部消息橫向滾動(dòng)通知效果實(shí)現(xiàn)
系統(tǒng)頂部展示一個(gè)橫向滾動(dòng)的消息通知,就是消息內(nèi)容從右往左一直滾動(dòng),這篇文章主要介紹了vue頂部消息橫向滾動(dòng)通知,需要的朋友可以參考下2024-02-02
關(guān)于vue3+echart5?遇到的坑?Cannot?read?properties?of?undefine
這篇文章主要介紹了vue3+echart5?遇到的坑?Cannot?read?properties?of?undefined?(reading?'type'),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-04-04
vue2.0項(xiàng)目實(shí)現(xiàn)路由跳轉(zhuǎn)的方法詳解
這篇文章主要介紹了vue2.0項(xiàng)目實(shí)現(xiàn)路由跳轉(zhuǎn)的詳細(xì)方法,非常不錯(cuò),具有一定的參考借鑒借鑒價(jià)值,需要的朋友可以參考下2018-06-06
vue3+vite assets動(dòng)態(tài)引入圖片的三種方法及解決打包后圖片路徑錯(cuò)誤不顯示的問(wèn)題
這篇文章主要介紹了vue3+vite assets動(dòng)態(tài)引入圖片的幾種方式,解決打包后圖片路徑錯(cuò)誤不顯示的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-03-03

