一. Vuex簡介/基本使用
1. 背景
傳統的元件見的互動模式如下: (可參考:https://www.cnblogs.com/yaopengfei/p/12326466.html)
(1). 父向子傳值:v-bind 屬性綁定
(2). 子向父傳值:v-on 事件綁定
(3). 兄弟元件之間共享資料: EventBus
$on 接收資料的那個元件
$emit 發送資料的那個元件
2. 簡介
(官方網站:https://vuex.vuejs.org/zh/)
(1). 定義
Vuex 是實作元件全局狀态(資料)管理的一種機制,可以友善的實作元件之間資料的共享。下圖是沒有vuex和有vuex時的處理模式。

(2). 好處
① 能夠在 vuex 中集中管理共享的資料,易于開發和後期維護
② 能夠高效地實作元件之間的資料共享,提高開發效率
③ 存儲在 vuex 中的資料都是響應式的,能夠實時保持資料與頁面的同步
(3). 什麼情況下采用Vuex
一般情況下,隻有元件之間共享的資料,才有必要存儲到 vuex 中;對于元件中的私有資料,依舊存儲在元件自身的 data 中即可。
3. 基本使用
(1). 已經存在的項目中引入Vuex
A. 安裝Vuex元件包
npm install vuex --save
B. 在main.js中導入Vuex
import Vuex from 'vuex'
Vue.use(Vuex)
C. 建立Vuex對象store
const store = new Vuex.Store({
// state 中存放的就是全局共享的資料
state: { count: 0 }
})
PS:通常将Vuex單獨封裝到一個store.js檔案中,然後在main.js中進行導入即可,然後挂載即可
main.js導入代碼,挂載見步驟D
import store from './store'
store.js代碼如下
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0
}
})
D. 将 store 對象挂載到 vue 執行個體中
new Vue({
store,
render: h => h(App)
}).$mount('#app')
(2). 建立項目時引入Vuex
使用圖形化界面進行建立項目,選擇插件的時候,要勾選Vuex,如下圖:
其它詳細步驟可參考:https://www.cnblogs.com/yaopengfei/p/14506321.html
建立後的項目:
src根目錄下,建立了一個Store檔案夾,下面有index.js檔案,用來處理vuex
index.js代碼如下:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
},
modules: {
}
})
View Code
main.js代碼如下:
import Vue from 'vue'
import App from './App.vue'
import store from './store'
Vue.config.productionTip = false
new Vue({
store,
render: h => h(App)
}).$mount('#app')
二. 核心功能
1. State
(1). 用途
State 提供唯一的公共資料源,所有共享的資料都要統一放到 Store 的 State 中進行存儲。
// 建立store資料源,提供唯一公共資料
const store = new Vuex.Store({
state: { count: 0 }
})
(2). 元件兩種通路方式
A. 直接 this.$store.state.全局資料名稱 通路
this.$store.state.count
B. 借助mapState
2. Mutation
Mutation 用于變更State中 的資料。
① 隻能通過 mutation 變更 State中 資料,不可以直接操作 Store 中的資料。(禁止 通過 this.$store.state.count 擷取後直接修改)
② 通過這種方式雖然操作起來稍微繁瑣一些,但是可以集中監控所有資料的變化。
注:Mutation中聲明方法,方法的第一個參數為state,可以擷取State中屬性,其它參數可以自定義。
A. 通過 this.$store.commit() 調用,下面分别是無參 和 有參的調用。
B. 通過mapMutations導入。
使用:
3. Action
Action 用于處理異步任務。
如果通過異步操作變更資料,必須通過 Action,而不能使用 Mutation,但是在 Action 中還是要通過觸發Mutation 的方式間接變更資料。
注:Action中聲明的是方法,方法的第一個參數為context,可以通過context.commit 調用 Mutation中的方法。其它參數可以自定義
A. 通過this.$store.dispatch()進行調用,下面分别是有參 和 無參的調用。
B. 通過導入mapActions調用。
調用:
4. Getter
Getter 用于對 State 中的資料進行加工處理形成新的資料。
① Getter 可以對 State 中已有的資料加工處理之後形成新的資料,類似 Vue 的計算屬性。
② State 中資料發生變化,Getter 的資料也會跟着變化。
注意:Getter中聲明的是方法,方法的第一個參數為state,可以擷取State中屬性。
// 定義 Getter
const store = new Vuex.Store({
state: {
count: 0
},
getters: {
showNum (state) {
return '目前最新的數量是【' + state.count + '】'
}
}
})
A. 通過this.$store.getters.名稱調用
<h3>{{$store.getters.showNum}}</h3>
B. 借助mapGetters調用
<h3>{{showNum}}</h3>
三. 案例演練
1. 要求
全局維護1個count變量,分别實作用兩種模式實作: 自增1、自增N、異步自增1、異步自增N;自減1、自減N、異步自減1、異步自減N;
2. 實作思路
(1). 聲明1個Add元件 和 Sub元件,分别用來處理自增 和 自減效果。導入App.vue中。
(2). 在Vuex對應的index檔案中的
state:聲明count變量
getter:修飾count變量
mutation:聲明自增、自減的同步方法
Action:聲明自增、自減的異步方法
(3). 在Add元件中通過 this.$store.state 、this.$store.getter、 this.$store.commit、this.$store.dispatch的方式調用。
在Sub元件中通過 import { mapState, mapMutations, mapActions, mapGetters } from 'vuex' 的方式進行調用。
3. 代碼分享
Vuex對應
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 0
},
// 隻有 mutations 中定義的函數,才有權利修改 state 中的資料
// 裡面聲明的方法,第一個參數為固定值state,用于擷取state中的值
mutations: {
add (state) {
// 不要在 mutations 函數中,執行異步操作!!!
// setTimeout(() => {
// state.count++
// }, 1000)
state.count++
},
addN (state, step) {
state.count += step
},
sub (state) {
state.count--
},
subN (state, step) {
state.count -= step
}
},
actions: {
addAsync (context) {
setTimeout(() => {
// 在 actions 中,不能直接修改 state 中的資料;
// 必須通過 context.commit() 觸發某個 mutation 才行
context.commit('add')
}, 1000)
},
addNAsync (context, step) {
setTimeout(() => {
context.commit('addN', step)
}, 1000)
},
subAsync (context) {
setTimeout(() => {
context.commit('sub')
}, 1000)
},
subNAsync (context, step) {
setTimeout(() => {
context.commit('subN', step)
}, 1000)
}
},
getters: {
showNum (state) {
return '目前最新的數量是【' + state.count + '】'
}
}
})
Add元件
<template>
<div>
<h3>目前最新的count值為:{{$store.state.count}}</h3>
<h3>{{$store.getters.showNum}}</h3>
<button @click="btnHandler1">+1</button>
<button @click="btnHandler2">+N</button>
<button @click="btnHandler3">+1 Async</button>
<button @click="btnHandler4">+N Async</button>
</div>
</template>
<script>
export default {
data () {
return {}
},
methods: {
btnHandler1 () {
this.$store.commit('add')
},
btnHandler2 () {
// commit 的作用,就是調用 某個 mutation 函數
this.$store.commit('addN', 3)
},
// 異步地讓 count 自增 +1
btnHandler3 () {
// 這裡的 dispatch 函數,專門用來觸發 action
this.$store.dispatch('addAsync')
},
btnHandler4 () {
this.$store.dispatch('addNAsync', 5)
}
}
}
</script>
<style>
</style>
Sub元件
<template>
<div>
<h3>目前最新的count值為:{{count}}</h3>
<h3>{{showNum}}</h3>
<button @click="btnHandler1">-1</button>
<button @click="subN(3)">-N</button>
<button @click="subAsync">-1 Async</button>
<button @click="subNAsync(5)">-N Async</button>
</div>
</template>
<script>
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'
export default {
data () {
return {}
},
computed: {
...mapState(['count']),
...mapGetters(['showNum'])
},
methods: {
...mapMutations(['sub', 'subN']),
...mapActions(['subAsync', 'subNAsync']),
btnHandler1 () {
this.sub()
}
}
}
</script>
<style>
</style>
App.vue
<template>
<div id="app">
<my-add></my-add>
<p>---------------------------------</p>
<my-sub></my-sub>
</div>
</template>
<script>
import Add from './components/Add.vue'
import Sub from './components/Sub.vue'
export default {
name: 'App',
components: {
'my-add': Add,
'my-sub': Sub
}
}
</script>
<style>
</style>
!
- 作 者 : Yaopengfei(姚鵬飛)
- 部落格位址 : http://www.cnblogs.com/yaopengfei/
- 聲 明1 : 如有錯誤,歡迎讨論,請勿謾罵^_^。
- 聲 明2 : 原創部落格請在轉載時保留原文連結或在文章開頭加上本人部落格位址,否則保留追究法律責任的權利。