這篇文章主要講解的是對vuex技術棧的實戰解析如有說的不好的地方,望大家指點。
1.實戰背景
最近在做一個單頁面的管理後台項目,爲了提高開發效率,使用了Vue框架來開發。爲了使各個部分的功能,獨立結構更加清晰,于是就拆分了很多組件,但是組件與組件之間數據共享成了一個問題,父子組件實現起來相對簡單,prop,$emit,$on就能搞定。除此之外,有很多兄弟組件和跨多級組件,實現起來過程繁瑣,在多人協同開發上,不利于統一管理,于是,開始了Vue的生態之一的Vux實踐之旅。
2.概述
每一個 Vuex 應用的核心就是 store(倉庫)。“store”基本上就是一個容器,它包含著你的應用中大部分的狀態 (state)。 Vuex 和單純的全局對象有以下兩點不同: 1.Vuex 的狀態存儲是響應式的。當 Vue 組件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那麽相應的組件也會相應地得到高效更新; 2.你不能直接改變 store 中的狀態。改變 store 中的狀態的唯一途徑就是顯式地提交 (commit) mutation。這樣使得我們可以方便地跟蹤每一個狀態的變化,從而讓我們能夠實現一些工具幫助我們更好地了解我們的應用
3.安裝使用
3.1.使用Vue-cli開發安裝vue包
cnpm install vuex –save
3.2.在src目錄下創建store文件夾並創建index.js如下(src/store/index.js)
import Vue from ‘vue’
import Vuex from ‘vuex’
Vue.use(Vuex);
export default new Vuex.Store({
state: {
},
getters: {
},
mutations: {
},
actions: {
}
});
然後在src文件下的main.js中使用
import Vue from ‘vue’
import App from ‘./App’
import store from ‘./store’
Vue.config.productionTip = false
new Vue({
el: ‘#app’,
store,
components: { App },
template: ‘<App/>’
})
4.用法簡介
4.1.state state是保存共享數據的,現在改store/index.js如下:
state: {
count:0
},
在components目錄下創建Index.vue如:
<template>
<div class=”index”>
{{count}}
</div>
</template>
<script>
export default {
name: “index”,
computed:{
count(){
return this.$store.state.count;
}
}
}
</script>
結果如下:
通過組件的計算屬性來保存state裏面的值,那麽問題來了,如果store太多的話,我們組件裏面的計算屬性豈不是成了這個樣子:
computed:{
count(){
return this.$store.state.count;
},
stateA(){
return this.$store.state.stateA;
},
stateB(){
return this.$store.state.stateB;
}
}
這樣獲取共享狀態的數據也沒有什麽問題不過看起來還是有大量的重複冗余代碼,我們可以使用 mapState 輔助函數幫助我們生成計算屬性,讓你少按幾次鍵: 當映射的計算屬性的名稱與 state 的子節點名稱相同時,我們也可以給 mapState 傳一個字符串數組。
import {mapState} from ‘vuex’
export default {
name: “index”,
computed:{
…mapState([‘count’])
}
使用 Vuex 並不意味著你需要將所有的狀態放入 Vuex。雖然將所有的狀態放到 Vuex 會使狀態變化更顯式和易調試,但也會使代碼變得冗長和不直觀。如果有些狀態嚴格屬于單個組件,最好還是作爲組件的局部狀態。
4.2.getter
有的時候我們需要對共享狀態裏面的某一個屬性做一些處理後再使用,我們可以把數據獲取後再在組件的計算屬性中處理,舉個例子如下:
// store/index.js
state: {
count:0,
numbers:[0,1,2,3,4,5,6,7,8]
},
// Index組件
<template>
<div class=”index”>
{{count}}
<br>
{{numbers.join()}}
</div>
</template>
<script>
import {mapState} from ‘vuex’
export default {
name: “index”,
computed:{
…mapState([‘count’]),
numbers(){
return this.$store.state.numbers.filter((item)=>{
return item>3;
})
}
}
}
</script>
結果如下:
那麽問題來了,如果多個組件都要做同樣的處理,我們就需要把一份代碼複制到多個地方,顯然是不大合理的,于是有了getter,可以理解爲組件裏面的計算屬性。示例如下:
/ store/index.js
getters: {
filterNumbers(state){
return state.numbers.filter((item)=>{
return item>3;
})
}
},
// Index組件
<template>
<div class=”index”>
{{count}}
<br>
{{filterNumbers.join()}}
</div>
</template>
<script>
import {mapState} from ‘vuex’
export default {
name: “index”,
computed:{
…mapState([‘count’]),
filterNumbers(){
return this.$store.getters.filterNumbers;
}
}
}
</script>
結果完全一樣,我們可以根據this.$store.getters.屬性名來獲取getters,也可以通過 mapGetters 輔助函數將 store 中的 getter 映射到局部計算屬性: 具體實現方式如下:
<template>
<div class=”index”>
{{count}}
<br>
{{filterNumbers.join()}}
<br>
{{antherNumbers.join()}}
</div>
</template>
<script>
import {mapState,mapGetters} from ‘vuex’
export default {
name: “index”,
computed:{
…mapState([‘count’]),6
…mapGetters([‘filterNumbers’]),
…mapGetters({
antherNumbers:’filterNumbers’
})
}
}
</script>
如果用同一名字直接把數組作爲參數,如果想改一個名字,可以傳入一個對象作爲參數,結果如下:
4.3.mutation
在組件內,來自store的數據只能讀取,不能手動改變,改變store中數據唯一的途徑就是顯示的提交mutations。Vuex 中的 mutation 非常類似于事件:每個 mutation 都有一個字符串的 事件類型 (type) 和 一個 回調函數 (handler)。這個回調函數就是我們實際進行狀態更改的地方,並且它會接受 state 作爲第一個參數。改變代碼如下:
// store/index.js
mutations: {
add(state){
state.count++;
}
},
// Index組件
**
<button @click=”add”>+</button>
**
methods:{
add(){
this.$store.commit(‘add’);
console.log(this.count);
}
連續點擊5次增加按鈕,發現count的值也改變了。當然,我們也可以傳參進去
// store/index.js
mutations: {
add(state,n){
state.count+=n;
}
},
// Index組件
**
<button @click=”add”>+</button>
**
methods:{
add(){
this.$store.commit(‘add’,10);
console.log(this.count);
}
觸發方法語句爲:this.$store.commit(方法名);也可以使用輔助函數mapMutations代替:
methods:{
…mapMutations([‘add’]),
}
4.4.action
前面我們講過,mutation有必須同步執行這個限制,我們在業務需求中有時候需要在獲取ajax請求數據之後再操作或定時器操作數據,這些都屬于異步請求,要用actions來實現。具體實現如下:
// store/index.js
mutations: {
changeCount(state){
state.count=3000;
}
},
actions: {
changeCount3000s(context){
setTimeout(()=>{
context.commit(‘changeCount’)
},3000)
// Index組件
<button @click=”changeCount3000s”>點擊按鈕3s後count的值改變</button>
methods:{
…mapMutations([‘add’]),
changeCount3000s(){
this.$store.dispatch(‘changeCount3000s’);
}
}
我們在點擊按鈕3s後count的值改變爲3000,我們可以通過this.$store.dispatch(方法名)來觸發事件,也可以通過輔助函數mapActions來觸發。
import {mapState,mapGetters,mapMutations,mapActions} from ‘vuex’
methods:{
…mapMutations([‘add’]),
…mapActions([‘changeCount3000s’])
}
學會以上幾個屬性的使用基本就可以滿足平時業務中的需求了,但使用Vuex會有一定的門檻和複雜性,它的主要使用場景是大型單頁面應用,如果你的項目不是很複雜,用一個bus也可以實現數據的共享,但是它在數據管理,維護,還只是一個簡單的組件,而Vuex可以更優雅高效地完成狀態管理,所以,是否使用Vuex取決于你的團隊和技術儲備。
結語
感謝您的觀看,如有不足之處,歡迎批評指正。