Vuex狀態(tài)機(jī)的快速了解與實(shí)例應(yīng)用
一. 速識(shí)概念:
1. 組件之間共享數(shù)據(jù)的方式:
通常有以下幾種方式:
- 父向子傳值:v-bind 屬性綁定;
- 子向父?jìng)髦担?strong>v-on 事件綁定;
- 兄弟組件之間共享數(shù)據(jù):EventBus;
2. vuex是什么:
- 按照官方的話來(lái)說(shuō),Vuex 是一個(gè)專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式。它采用集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測(cè)的方式發(fā)生變化。Vuex 也集成到 Vue 的官方調(diào)試工具 devtools extension (opens new window),提供了諸如零配置的 time-travel 調(diào)試、狀態(tài)快照導(dǎo)入導(dǎo)出等高級(jí)調(diào)試功能。
- 簡(jiǎn)單來(lái)說(shuō),Vuex就是實(shí)現(xiàn)組件全局狀態(tài)(數(shù)據(jù))管理的一種機(jī)制,可以方便的實(shí)現(xiàn)組件之間數(shù)據(jù)的共享。
3.使用vuex優(yōu)點(diǎn):
- 能夠在vuex中集中管理共享的數(shù)據(jù),易于開發(fā)和后期維護(hù)。
- 能夠高效地實(shí)現(xiàn)組件之間的數(shù)據(jù)共享, 提高開發(fā)效率。
- 存儲(chǔ)在vuex中的數(shù)據(jù)都是響應(yīng)式的,能夠?qū)崟r(shí)保持?jǐn)?shù)據(jù)與頁(yè)面的同步。
- 解決了非父子組件的消息傳遞(將數(shù)據(jù)存放在state中)。
- 減少了AJAX請(qǐng)求次數(shù),有些情景可以直接從內(nèi)存中的state獲取。
一般情況下,只有組件之間共享的數(shù)據(jù),才有必要存儲(chǔ)到vuex中。而對(duì)于組件中的私有數(shù)據(jù),就沒必要了,依舊存儲(chǔ)在組件自身的data中即可。當(dāng)然,如果你想要都存在vuex中也是可以的。
二. 基本使用:
1.安裝依賴包:
npm install vuex --save
2.導(dǎo)入依賴包:
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex)
3.創(chuàng)建store對(duì)象:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
//state中存放的就是全局共享的數(shù)據(jù)
state: {
count: 0
}
})
4. 將store對(duì)象掛載到vue實(shí)例中:
new Vue({
el: '#app',
store
})
此時(shí)所有組件就可以從store中獲取數(shù)據(jù)了。
三.創(chuàng)建項(xiàng)目:
下面為創(chuàng)建一個(gè)vue項(xiàng)目流程,后面會(huì)有案例:
(1)打開cmd窗口輸入 vue ui 打開vue的可視化面板:

(2)選擇新建項(xiàng)目路徑:

(3)命名:

(4)手動(dòng)選擇配置,注意用的是vue2版本:


(5)創(chuàng)建:

(6)下一步:

(7)創(chuàng)建成功,到對(duì)應(yīng)目錄打開vscode開始編程:

(8)運(yùn)行項(xiàng)目:

四. 講解前提:
前提(注意):
寫一個(gè)計(jì)數(shù)器小案例,從案例中配合概念能更快上手vuex。所以下面核心概念中的代碼部分是基于這個(gè)小案例來(lái)演示的。目標(biāo):寫兩個(gè)子組件,有一個(gè)公共count值,在父組件中,其中一個(gè)組件實(shí)現(xiàn)點(diǎn)擊后count值減1,一個(gè)組件實(shí)現(xiàn)點(diǎn)擊后count值增1。
父組件 App.vue 初始代碼:
<template>
<div id="app">
<my-add></my-add>
<p>--------------------</p>
<my-reduce></my-reduce>
</div>
</template>
<script>
// 引入組件
import Add from './components/Add.vue'
import Reduce from './components/Reduce.vue'
export default {
name: 'App',
data() {
return {
}
},
components: {
'my-add': Add,
'my-reduce': Reduce
}
}
</script>
子組件Add.vue初始代碼:
<template>
<div>
<p>count值為:</p>
<button>+1</button>
</div>
</template>
<script>
export default{
data() {
return {
}
},
}
</script>
子組件Reduce.vue初始代碼:
<template>
<div>
<p>count值為:</p>
<button>-1</button>
</div>
</template>
<script>
export default{
data() {
return {
}
},
}
</script>
store對(duì)象初始代碼為:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0
}
})
初始效果:

五.核心概念:
1.state:
按照官方的話來(lái)說(shuō),如下:Vuex 使用單一狀態(tài)樹——是的,用一個(gè)對(duì)象就包含了全部的應(yīng)用層級(jí)狀態(tài)。至此它便作為一個(gè)“唯一數(shù)據(jù)源 (SSOT)”而存在。這也意味著,每個(gè)應(yīng)用將僅僅包含一個(gè) store 實(shí)例。
簡(jiǎn)單來(lái)說(shuō),就是State提供唯一的公共數(shù)據(jù)源, 所有共享的數(shù)據(jù)都要統(tǒng)一放到Store的State中進(jìn)行存儲(chǔ)。
1.1 組件中訪問state的第一種方式:
組件中直接輸入以下命令:
this.$store.state.引用的數(shù)據(jù)名字
如在Add.vue子組件中引用:
<template>
<div>
<p>count值為:{{this.$store.state.count}}</p>
<button>+1</button>
</div>
</template>
//下面部分代碼跟前面一樣無(wú)改變,所以省略了
看效果,顯示了count的值為0:

1.2 組件中訪問state的第二種方式:
(1)從 vuex 中按需導(dǎo)入 mapState 函數(shù)
import { mapState } from 'vuex'
(2)通過(guò)剛才導(dǎo)入的mapState函數(shù),將當(dāng)前組件需要的全局?jǐn)?shù)據(jù),映射為當(dāng)前組件的computed計(jì)算屬性:
computed: {
...mapState([count])
}
小知識(shí):computed用來(lái)監(jiān)控自己定義的變量,該變量不在data里面聲明,直接在computed里面定義,然后就可以在頁(yè)面上進(jìn)行雙向數(shù)據(jù)綁定展示出結(jié)果或者用作其他處理;
如在Reduce.vue子組件中引用:
<template>
<div>
<p>count值為:{{count}}</p>
<button>-1</button>
</div>
</template>
<script>
import {mapState} from 'vuex'
export default{
data() {
return {
}
},
computed: {
...mapState(['count'])
}
}
</script>
看效果,同樣顯示了count的值為0:

2. mutation:
按照官方的話來(lái)說(shuō),更改 Vuex 的 store 中的狀態(tài)的唯一方法是提交 mutation。Vuex 中的 mutation 非常類似于事件:每個(gè) mutation 都有一個(gè)字符串的 事件類型 (type) 和 一個(gè) 回調(diào)函數(shù) (handler)。這個(gè)回調(diào)函數(shù)就是我們實(shí)際進(jìn)行狀態(tài)更改的地方,并且它會(huì)接受 state 作為第一個(gè)參數(shù)。
簡(jiǎn)單來(lái)說(shuō)就是Mutation用于變更Store中的數(shù)據(jù)。
①只能通過(guò)mutation變更Store數(shù)據(jù),不可以直接操作Store中的數(shù)據(jù)。
②通過(guò)這種方式雖然操作起來(lái)稍微繁瑣一些,但是可以集中監(jiān)控所有數(shù)據(jù)的變化。
比如,要實(shí)現(xiàn)count值自增加1的操作,那就在先motations里定義一個(gè)自增加1的函數(shù)。然后對(duì)應(yīng)子組件想用,該組件就直接引入mutation并調(diào)用對(duì)應(yīng)的函數(shù)就好。
如下,Add.vue子組件要實(shí)現(xiàn)自增加1功能:
先在狀態(tài)機(jī)里的mutations里定義一個(gè)能實(shí)現(xiàn)自增的函數(shù)add:
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
//自增加1函數(shù)
add(state){
state.count++
}
}
})
2.1 觸發(fā)mutation的第一種方式:
Add.vue子組件里給按鈕綁定點(diǎn)擊事件,并觸發(fā)mutation:
<template>
<div>
<p>count值為:{{this.$store.state.count}}</p>
<button @click="btnAdd">+1</button>
</div>
</template>
<script>
export default{
data() {
return {
}
},
methods: {
btnAdd() {
// 第一種引入mutation的方式,觸發(fā)add函數(shù)
this.$store.commit('add')
}
}
}
</script>
看效果實(shí)現(xiàn)了點(diǎn)擊自增:

2.2 觸發(fā)mutation并傳參數(shù):
當(dāng)然,當(dāng)組件里調(diào)用mutation里函數(shù)時(shí),也是可以傳參數(shù)的。
比如,有一個(gè)自增函數(shù),但增多少看調(diào)用時(shí)傳入的參數(shù):
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
// 傳入?yún)?shù),第一個(gè)一定是state,第二個(gè)為傳入的參數(shù)
//自增加 n 的函數(shù)
addN(state,n){
state.count+= n
}
}
})
對(duì)應(yīng)組件調(diào)用時(shí)要傳入?yún)?shù):
methods: {
btnAdd2() {
// 引入mutation的方式,觸發(fā)addN函數(shù)
// 并傳參,自增加6吧
this.$store.commit('addN',6)
}
}
2.1 觸發(fā)mutation的第二種方式:
(1)從 vuex 中按需導(dǎo)入 mapMutations 函數(shù)
import { mapMutations } from 'vuex'
(2)通過(guò)剛才導(dǎo)入的mapMutations函數(shù),將需要的mutations函數(shù),映射為當(dāng)前組件的methods方法:
methods: {
...mapMutations(['add','addN'])
}
實(shí)戰(zhàn),實(shí)現(xiàn)Reduce.vue組件的點(diǎn)擊自減1的功能要求:
狀態(tài)機(jī)添加自減函數(shù):
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
//自增加1函數(shù)
add(state){
state.count++
},
// 自減1的函數(shù)
sub(state){
state.count--
}
}
})
Reduce.vue組件點(diǎn)擊按鈕實(shí)現(xiàn)自減1:
<template>
<div>
<p>count值為:{{count}}</p>
<button @click="btnSub">-1</button>
</div>
</template>
<script>
//導(dǎo)入
import {mapState,mapMutations} from 'vuex'
export default{
data() {
return {
}
},
computed: {
...mapState(['count'])
},
methods: {
// 映射mutation里的sub函數(shù)
...mapMutations(['sub']),
// 要自減,調(diào)用sub函數(shù)
btnSub(){
this.sub()
}
}
}
</script>
看效果:

3.Action:
至此,第四大點(diǎn)里的案例已經(jīng)完成,已經(jīng)實(shí)現(xiàn)了自增和自減,現(xiàn)在對(duì)案例做改進(jìn),要我們點(diǎn)擊按鈕一秒后再自增和自減,該怎么實(shí)現(xiàn)?可以在狀態(tài)機(jī)里的mutation里的函數(shù)是加一個(gè)1秒定時(shí)器嗎,這肯定是不行的,因?yàn)?strong>mutation里不支持異步操作,那咋辦,當(dāng)當(dāng)當(dāng),Action閃亮登場(chǎng)。
Action 可以包含任意異步操作,所以它用來(lái)處理異步任務(wù)。
Action 提交的是 mutation,而不是直接變更狀態(tài)。記住它并不能直接修改state里的數(shù)據(jù),只有mutation能修改。就是說(shuō),如果通過(guò)異步操作變更數(shù)據(jù),必須通過(guò)Action,而不能使用Mutation,但是在Action中還是要通過(guò)觸發(fā)Mutation的方式間接變更數(shù)據(jù)。
先在狀態(tài)機(jī)里定義Action:
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
//自增加1函數(shù)
add(state){
state.count++
},
// 自減1的函數(shù)
sub(state){
state.count--
}
},
// 定義action,里面的addAsync函數(shù)實(shí)現(xiàn)1秒后執(zhí)行mutation里的add函數(shù)
actions: {
addAsync(context) {
setTimeout(()=>{
// 必須通過(guò)context.commit()觸發(fā)mutation才行
context.commit('add')
},1000)
}
}
})
Action 函數(shù)接受一個(gè)與 store 實(shí)例具有相同方法和屬性的 context 對(duì)象,因此你可以調(diào)用 context.commit 提交一個(gè) mutation。
3.1 觸發(fā)Action的第一種方式:
更改組件Add.vue代碼,引入Action,實(shí)現(xiàn)異步自增操作。
<template>
<div>
<p>count值為:{{this.$store.state.count}}</p>
<button @click="btnAdd">+1</button>
</div>
</template>
<script>
export default{
data() {
return {
}
},
methods: {
btnAdd() {
// 第一種引入Action的方式,觸發(fā)addAsync函數(shù)
// 這里的dispatch專門用來(lái)調(diào)用action函數(shù)
this.$store.dispatch('addAsync')
}
}
}
</script>
看效果,實(shí)現(xiàn)1秒后自增:

3.2 觸發(fā)Action異步任務(wù)并傳參數(shù):
當(dāng)然,當(dāng)組件里調(diào)用action里函數(shù)時(shí),也是可以傳參數(shù)的。
比如,有一個(gè)點(diǎn)擊1秒后才執(zhí)行的自增函數(shù),但增多少看調(diào)用時(shí)傳入的參數(shù):
定義:
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
// 傳入?yún)?shù),第一個(gè)一定是state,第二個(gè)為傳入的參數(shù)
//自增加 n 的函數(shù)
addN(state,n){
state.count+= n
}
},
actions: {
// 有參數(shù) n,這個(gè)n又傳給了mutation里的addN函數(shù)
addNAsync(context,n) {
setTimeout(()=>{
context.commit('addN',n)
},1000)
}
}
})
對(duì)應(yīng)組件調(diào)用時(shí)要傳入?yún)?shù):
methods: {
btnAdd2() {
// 調(diào)用dispatch函數(shù)
// 觸發(fā)action時(shí)傳參數(shù),為 6 吧,表示自增6
this.$store.dispatch('addNAsync',6)
}
}
3.3 觸發(fā)Action的第二種方式:
(1)從 vuex 中按需導(dǎo)入 mapActions 函數(shù)
import { mapActions } from 'vuex'
(2)通過(guò)剛才導(dǎo)入的mapActions函數(shù),將需要的actions函數(shù),映射為當(dāng)前組件的methods方法:
methods: {
...mapActions(['add','addN'])
}
實(shí)戰(zhàn),實(shí)現(xiàn)Reduce.vue組件的點(diǎn)擊一秒后自減1的功能要求:
定義actions里的subAsync為一秒后自減函數(shù):
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
//自增加1函數(shù)
add(state){
state.count++
},
// 自減1的函數(shù)
sub(state){
state.count--
}
},
actions: {
addAsync(context) {
setTimeout(()=>{
context.commit('add')
},1000)
},
subAsync(context) {
setTimeout(()=>{
context.commit('sub')
},1000)
}
}
})
更改Reduce.vue代碼,實(shí)現(xiàn)功能:
<template>
<div>
<p>count值為:{{count}}</p>
<button @click="btnSub">-1</button>
</div>
</template>
<script>
//導(dǎo)入
import {mapState,mapActions} from 'vuex'
export default{
data() {
return {
}
},
computed: {
...mapState(['count'])
},
methods: {
// 映射Action里的函數(shù)
...mapActions(['subAsync']),
// 要自減,調(diào)用subAsync函數(shù)
btnSub(){
this.subAsync()
}
}
}
</script>
看效果:

4. Getter:
Getter用于對(duì)Store中的數(shù)據(jù)進(jìn)行加工處理形成新的數(shù)據(jù)。且要注意的是它并不會(huì)修改state中的數(shù)據(jù)。
①Getter 可以對(duì)Store中已有的數(shù)據(jù)加工處理之后形成新的數(shù)據(jù),類似Vue的計(jì)算屬性。
②Store 中數(shù)據(jù)發(fā)生變化,Getter 的數(shù)據(jù)也會(huì)跟著變化。
如,有一個(gè)返回當(dāng)前count+1的getter函數(shù):
export default new Vuex.Store({
state: {
count: 0
},
getters: {
showNum(state){
return`當(dāng)前count值加1為:${state.count+1}`
}
}
})
4.1 觸發(fā)getters的第一種方式:
this.$store.getters.名稱
在App.vue組件中顯示:
<template>
<div id="app">
<my-add></my-add>
<p>--------------------</p>
<my-reduce></my-reduce>
<p>--------------------</p>
<h3>{{this.$store.getters.showNum}}</h3>
</div>
</template>
效果:

4.2觸發(fā)getters的第二種方式:
(1)從 vuex 中按需導(dǎo)入 mapGetters 函數(shù)
import { mapGetters } from 'vuex'
(2)通過(guò)剛才導(dǎo)入的mapGetters函數(shù),將當(dāng)前組件需要的全局?jǐn)?shù)據(jù),映射為當(dāng)前組件的computed計(jì)算屬性:
computed: {
...mapGetters(['showNum'])
}
還是在App.vue中使用把:
<template>
<div id="app">
<my-add></my-add>
<p>--------------------</p>
<my-reduce></my-reduce>
<p>--------------------</p>
<h3>{{showNum}}</h3>
</div>
</template>
<script>
// 引入組件
import Add from './components/Add.vue'
import Reduce from './components/Reduce.vue'
// 導(dǎo)入 mapGetters函數(shù)
import {mapGetters} from 'vuex'
export default {
name: 'App',
data() {
return {
}
},
components: {
'my-add': Add,
'my-reduce': Reduce
},
// 引入 getter
computed: {
...mapGetters(['showNum'])
}
}
</script>
看,一樣的效果:

六.總結(jié):
到此這篇關(guān)于Vuex狀態(tài)機(jī)的快速了解與實(shí)例應(yīng)用的文章就介紹到這了,更多相關(guān)Vuex狀態(tài)機(jī)應(yīng)用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue 中使用 vxe-table 制作可編輯表格的使用過(guò)程
這篇文章主要介紹了vue 中使用 vxe-table 制作可編輯表格的使用過(guò)程,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-08-08
Vue實(shí)現(xiàn)帶進(jìn)度條的文件拖動(dòng)上傳功能
這篇文章主要介紹了Vue實(shí)現(xiàn)帶進(jìn)度條的文件拖動(dòng)上傳功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有參考借鑒價(jià)值,需要的朋友可以參考下2018-02-02
Vue中實(shí)現(xiàn)表單地區(qū)選擇與級(jí)聯(lián)聯(lián)動(dòng)示例詳解
這篇文章主要為大家介紹了Vue中實(shí)現(xiàn)表單地區(qū)選擇與級(jí)聯(lián)聯(lián)動(dòng)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
vue使用echarts實(shí)現(xiàn)中國(guó)地圖和點(diǎn)擊省份進(jìn)行查看功能
這篇文章主要介紹了vue使用echarts實(shí)現(xiàn)中國(guó)地圖和點(diǎn)擊省份進(jìn)行查看功能,本文通過(guò)實(shí)例代碼給大家詳細(xì)講解,對(duì)vue echarts 中國(guó)地圖相關(guān)知識(shí)感興趣的朋友一起看看吧2022-12-12
Vue3 響應(yīng)式高階用法之triggerRef()的使用
在Vue3響應(yīng)式系統(tǒng)中,shallowRef僅追蹤頂層屬性的變化,當(dāng)需要對(duì)內(nèi)層屬性作出反應(yīng)時(shí),可使用triggerRef()方法手動(dòng)觸發(fā)更新,本文介紹了triggerRef()的應(yīng)用場(chǎng)景、基本用法、功能和最佳實(shí)踐,感興趣的可以了解一下2024-09-09
Vue3 openlayers加載瓦片地圖并手動(dòng)標(biāo)記坐標(biāo)點(diǎn)功能
這篇文章主要介紹了 Vue3 openlayers加載瓦片地圖并手動(dòng)標(biāo)記坐標(biāo)點(diǎn)功能,我們這里用vue/cli創(chuàng)建,我用的node版本是18.12.1,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2024-04-04

