第5章:vuex
- 1 求和案例 純vue版
- 2 vuex工作原理圖
- 3 vuex案例
- 3.1 搭建vuex環境
- 錯誤寫法
- 正確寫法
- 3.2 求和案例vuex版
- 細節分析
- 源代碼
- 4 getters配置項
- 4.1 細節
- 4.2 源代碼
- 5 mapState與mapGetters
- 5.1 總結
- 5.2 細節分析
- 5.3 源代碼
- 6 mapActions與mapMutations
- 6.1 總結
- 6.2 細節
- 6.3 源代碼
- 7 多組件共享數據
- 7.1 細節
- 7.2 源代碼
- 8 vuex模塊化 + namespace
- 8.1 總結
- 8.2 第一部分
- 細節問題
- 8.3 第二部分
- 細節問題
- 8.4 源代碼
1 求和案例 純vue版
這里只需要住一個問題,就是Count組件的v-model.number=“n”,如果沒有number,這個n就是個字符串。
src/components/Count.vue
<template><div><h1>當前求和為:{{sum}}</h1><select v-model.number="n"><option value="1">1</option><option value="2">2</option><option value="3">3</option></select><button @click="increment">+</button><button @click="decrement">-</button><button @click="incrementOdd">當前求和為奇數再加</button><button @click="incrementWait">等一等再加</button></div>
</template><script>export default {name:'Count',data() {return {n:1, //用戶選擇的數字sum:0 //當前的和}},methods: {increment(){this.sum += this.n},decrement(){this.sum -= this.n},incrementOdd(){if(this.sum % 2){this.sum += this.n}},incrementWait(){setTimeout(()=>{this.sum += this.n},500)},},}
</script><style lang="css">button{margin-left: 5px;}
</style>
src/App.vue
<template><div><Count/></div>
</template><script>import Count from './components/Count'export default {name:'App',components:{Count},}
</script>
src/main.js
//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//引入插件
import vueResource from 'vue-resource'
//關閉Vue的生產提示
Vue.config.productionTip = false
//使用插件
Vue.use(vueResource)//創建vm
new Vue({el:'#app',render: h => h(App),beforeCreate() {Vue.prototype.$bus = this}
})
2 vuex工作原理圖
以求和案例為例,用sum來表示當前的和,vuex會交時state保管,此時sum為0。
- State是一個Object類型對象,可以存儲很多數據,例如todos,sum等。
接下來過程如下:
- Count組件調用dispatch,它是一個函數,要傳兩個參數,一個是進行的動作類型,一個是數據,即dispatch(‘jia’,2)。
- Actions也是一個Object類型對象,此時Actions對象里面必然有一組key value為jia:function,此時函數被調用,就收到了2,function函數里面就會調用commit(‘jia’,2)。
- Mutations也是一個Object類型對象,此時Mutations對象里面必然有一組key value為jia:function,function會拿到兩個東西,一個是state,一個是2,隨后function里面就寫state.sum += 2即可,然后底層就自動走了Mutate。
- 最終state里面保存的sum的值就變為了2。
- vuex會重新解析組件,再重新渲染頁面,于是頁面的sum也變成了2
Actions設計的目的是為了和后端交互的,例如dispatch(‘chu’),有動作類型,但沒有所對應的值,此時就要問后端了,后端服務器返回9,如下:
如果你并不需要和后端交互,就可以直接和Mutations交互,如下:
注意到Devtools即開發者工具是和Mutations進行交互的。
Actions、Mutations和State統一經過一個東西的管理,如下:
也就是說調用dispatch等方法時,是由store提供的,如下:
3 vuex案例
3.1 搭建vuex環境
2022年2月7日,Vue3已經成為了默認版本,vuex也同時更新到4版本,即執行命令:npm i vuex,安裝的是vuex的4版本,而vuex的4版本只能在vue3使用。
- Vue2中,要用vuex的3版本,執行命令:npm i vuex@3
- Vue3中,要用vuex的4版本
錯誤寫法
首先在src下面創建一個store文件夾,如下:
index里面代碼如下:
緊接著在main.js引入store,由于文件名稱是index.js,所以可以直接省略名字,腳手架認識,如下:
此時好像環境搭建完畢,但這樣會出錯,如下:創建store實例之前就要使用Vue.use(Vuex)
回到main.js代碼分析,首先得把綠色框文件里得代碼執行完了,我才能收到store,隨后才走粉色框代碼。
- 這樣就導致了先創建store實例,因為綠色框文件即index.js創建了一個store實例。
哪怕換順序也沒用,import語句有優先級,會優先執行,不管順序。
- 即首先掃描所有import語句,按照import語句代碼順序,全部先執行import語句。
正確寫法
首先在src下面創建一個store文件夾,如下:
index里面代碼如下:
緊接著在main.js引入store,由于文件名稱是index.js,所以可以直接省略名字,腳手架認識,如下:
3.2 求和案例vuex版
細節分析
一般來說共享是由兩個及以上的組件才叫共享,如下:
但在這個案例中僅僅使用了Count組件,主要是為了學習vuex的開發流程。
細節一:actions
actions中函數的第一個參數是context,稱之為miniStore,其內容如下:
actions中函數的第二個參數就是所傳遞的值。
一般commit的時候會大寫JIA,目的是做個區分,一看到大寫JIA,就知道是mutations里的。
細節一:mutations
mutations中函數的第一個參數是state,并且進行了加工,加上了get和set,如下:
mutations中函數的第二個參數就是所傳遞的值。
細節三
如下所示,綠色框函數要作一些判斷,它是有存在意義的,而紅色框函數沒有任何存在意義,因此刪掉
刪掉之后,直接調用commit即可,如下:
源代碼
src/components/Count.vue
<template><div><h1>當前求和為:{{$store.state.sum}}</h1><select v-model.number="n"><option value="1">1</option><option value="2">2</option><option value="3">3</option></select><button @click="increment">+</button><button @click="decrement">-</button><button @click="incrementOdd">當前求和為奇數再加</button><button @click="incrementWait">等一等再加</button></div>
</template><script>export default {name:'Count',data() {return {n:1, //用戶選擇的數字}},methods: {increment(){this.$store.commit('JIA',this.n)},decrement(){this.$store.commit('JIAN',this.n)},incrementOdd(){this.$store.dispatch('jiaOdd',this.n)},incrementWait(){this.$store.dispatch('jiaWait',this.n)},},mounted() {console.log('Count',this)},}
</script><style lang="css">button{margin-left: 5px;}
</style>
src/store/index.js
//該文件用于創建Vuex中最為核心的store
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//應用Vuex插件
Vue.use(Vuex)//準備actions——用于響應組件中的動作
const actions = {/* jia(context,value){console.log('actions中的jia被調用了')context.commit('JIA',value)},jian(context,value){console.log('actions中的jian被調用了')context.commit('JIAN',value)}, */jiaOdd(context,value){console.log('actions中的jiaOdd被調用了')if(context.state.sum % 2){context.commit('JIA',value)}},jiaWait(context,value){console.log('actions中的jiaWait被調用了')setTimeout(()=>{context.commit('JIA',value)},500)}
}
//準備mutations——用于操作數據(state)
const mutations = {JIA(state,value){console.log('mutations中的JIA被調用了')state.sum += value},JIAN(state,value){console.log('mutations中的JIAN被調用了')state.sum -= value}
}
//準備state——用于存儲數據
const state = {sum:0 //當前的和
}//創建并暴露store
export default new Vuex.Store({actions,mutations,state,
})
src/App.vue
<template><div><Count/></div>
</template><script>import Count from './components/Count'export default {name:'App',components:{Count},mounted() {// console.log('App',this)},}
</script>
src/main.js
//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//引入插件
import vueResource from 'vue-resource'
//引入store
import store from './store'//關閉Vue的生產提示
Vue.config.productionTip = false
//使用插件
Vue.use(vueResource)//創建vm
new Vue({el:'#app',render: h => h(App),store,beforeCreate() {Vue.prototype.$bus = this}
})
4 getters配置項
4.1 細節
當前有一個新需求:還要顯示當前求和放大十倍后的結果。
最好不要像如下這樣寫,考慮一下,假設程序員要對state的sum進行一些加工,而且是一些很復雜的數學運算,而且很多程序員要使用這樣的功能,這樣就不適合像如下這樣寫。
- 使用計算屬性也不行,它不能跨組件
直接在store的index文件夾進行配置,如下:
- state就如同data,而getters就如同computed一樣
組件中讀取數據:$store.getters.bigSum
。直接看代碼即可
4.2 源代碼
在求和案例vuex版基礎上,要修改的代碼有:
src/components/Count.vue
<template><div><h1>當前求和為:{{$store.state.sum}}</h1><h3>當前求和放大10倍為:{{$store.getters.bigSum}}</h3><select v-model.number="n"><option value="1">1</option><option value="2">2</option><option value="3">3</option></select><button @click="increment">+</button><button @click="decrement">-</button><button @click="incrementOdd">當前求和為奇數再加</button><button @click="incrementWait">等一等再加</button></div>
</template><script>export default {name:'Count',data() {return {n:1, //用戶選擇的數字}},methods: {increment(){this.$store.commit('JIA',this.n)},decrement(){this.$store.commit('JIAN',this.n)},incrementOdd(){this.$store.dispatch('jiaOdd',this.n)},incrementWait(){this.$store.dispatch('jiaWait',this.n)},},mounted() {console.log('Count',this.$store)},}
</script><style lang="css">button{margin-left: 5px;}
</style>
src/store/index.js
//該文件用于創建Vuex中最為核心的store
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//應用Vuex插件
Vue.use(Vuex)//準備actions——用于響應組件中的動作
const actions = {/* jia(context,value){console.log('actions中的jia被調用了')context.commit('JIA',value)},jian(context,value){console.log('actions中的jian被調用了')context.commit('JIAN',value)}, */jiaOdd(context,value){console.log('actions中的jiaOdd被調用了')if(context.state.sum % 2){context.commit('JIA',value)}},jiaWait(context,value){console.log('actions中的jiaWait被調用了')setTimeout(()=>{context.commit('JIA',value)},500)}
}
//準備mutations——用于操作數據(state)
const mutations = {JIA(state,value){console.log('mutations中的JIA被調用了')state.sum += value},JIAN(state,value){console.log('mutations中的JIAN被調用了')state.sum -= value}
}
//準備state——用于存儲數據
const state = {sum:0 //當前的和
}
//準備getters——用于將state中的數據進行加工
const getters = {bigSum(state){return state.sum*10}
}//創建并暴露store
export default new Vuex.Store({actions,mutations,state,getters
})
5 mapState與mapGetters
5.1 總結
5.2 細節分析
我們多配置兩個數據,分別為school和subject,如下:當使用state的很多數據時候,會多次調用store.state.xxx,這樣很麻煩。
最簡單的方式是用計算屬性解決,但是要程序員一次一次的配置,也會很麻煩。
vuex的設計者提供了mapState方法,它可以幫我們批量生成粉色框的代碼,因為它們共同點都是從state讀取數據。
首先要引入mapState,如下:
看看mapState輸出是什么
比如要生成state的sum相對應函數,如下:
我們可以寫簡寫形式,即前面的’he’去掉’',但sum不行,它是一個表達式,其余的也同理,如下:
輸出x,可以看到,它為我們生成了函數,如下:
在computed里面配置mapstate
我們會發現,像上述這樣配置,會發生報錯,這是因為mapState本身是一個對象,computed又是對象,不可能直接在對象里面寫對象。
在對象里面寫對象的方法
先看一個例子
直接在對象前面加三個點,意思是把obj2里面的每一組key和value展開放入到obj里面
最終輸出如下:
因此我們要在mapState加三個點,如下:
還有一種數組寫法,并且要求同名,如下:
由于同名可以簡寫,簡寫的時候必須要’',以sum:'sum’為例,如果簡寫成sum,最終含義就是sum:sum,進而去讀取sum變量,這就報錯了。
舉個例子,只有是變量的時候,簡寫才能直接不要’‘,如下:
由于a是變量,所以簡寫不需要’’
所以最終簡寫形式如下:
對于getters同理也有mapGetters,一樣的用法,直接看代碼即可。
5.3 源代碼
在求和案例vuex版基礎上,要修改的代碼有:
src/components/Count.vue
<template><div><h1>當前求和為:{{sum}}</h1><h3>當前求和放大10倍為:{{bigSum}}</h3><h3>我在{{school}},學習{{subject}}</h3><select v-model.number="n"><option value="1">1</option><option value="2">2</option><option value="3">3</option></select><button @click="increment">+</button><button @click="decrement">-</button><button @click="incrementOdd">當前求和為奇數再加</button><button @click="incrementWait">等一等再加</button></div>
</template><script>import {mapState,mapGetters} from 'vuex'export default {name:'Count',data() {return {n:1, //用戶選擇的數字}},computed:{//靠程序員自己親自去寫計算屬性/* sum(){return this.$store.state.sum},school(){return this.$store.state.school},subject(){return this.$store.state.subject}, *///借助mapState生成計算屬性,從state中讀取數據。(對象寫法)// ...mapState({he:'sum',xuexiao:'school',xueke:'subject'}),//借助mapState生成計算屬性,從state中讀取數據。(數組寫法)...mapState(['sum','school','subject']),/* ******************************************************************** *//* bigSum(){return this.$store.getters.bigSum}, *///借助mapGetters生成計算屬性,從getters中讀取數據。(對象寫法)// ...mapGetters({bigSum:'bigSum'})//借助mapGetters生成計算屬性,從getters中讀取數據。(數組寫法)...mapGetters(['bigSum'])},methods: {increment(){this.$store.commit('JIA',this.n)},decrement(){this.$store.commit('JIAN',this.n)},incrementOdd(){this.$store.dispatch('jiaOdd',this.n)},incrementWait(){this.$store.dispatch('jiaWait',this.n)},},mounted() {const x = mapState({he:'sum',xuexiao:'school',xueke:'subject'})console.log(x)},}
</script><style lang="css">button{margin-left: 5px;}
</style>
src/store/index.js
//該文件用于創建Vuex中最為核心的store
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//應用Vuex插件
Vue.use(Vuex)//準備actions——用于響應組件中的動作
const actions = {/* jia(context,value){console.log('actions中的jia被調用了')context.commit('JIA',value)},jian(context,value){console.log('actions中的jian被調用了')context.commit('JIAN',value)}, */jiaOdd(context,value){console.log('actions中的jiaOdd被調用了')if(context.state.sum % 2){context.commit('JIA',value)}},jiaWait(context,value){console.log('actions中的jiaWait被調用了')setTimeout(()=>{context.commit('JIA',value)},500)}
}
//準備mutations——用于操作數據(state)
const mutations = {JIA(state,value){console.log('mutations中的JIA被調用了')state.sum += value},JIAN(state,value){console.log('mutations中的JIAN被調用了')state.sum -= value}
}
//準備state——用于存儲數據
const state = {sum:0, //當前的和school:'尚硅谷',subject:'前端'
}
//準備getters——用于將state中的數據進行加工
const getters = {bigSum(state){return state.sum*10}
}//創建并暴露store
export default new Vuex.Store({actions,mutations,state,getters
})
6 mapActions與mapMutations
6.1 總結
6.2 細節
我們需要優化的是方法,如下:
首先使用mapMutations修改,如下:
但當點擊+1之后,發生如下錯誤:
我們讓JIA輸出value看看什么情況,如下:
可以看到,這個value是一個事件,如下:
可以看到,mapMutations生成的函數,需要傳遞參數。
可以看到,我們調用函數時,并沒有傳遞參數,所以默認傳的參數是event,如下:
因此在調用函數時,要傳入參數,如下:
如果不想在函數里面傳參,還可以用下面這個方法(但我覺得復雜了):
我們采取函數傳參的方法,此時mapMutations還可以使用數組方法,并使用簡寫形式,如下:
此時調用函數處為:
mapActions同理,不再過多說明,直接看源代碼。
6.3 源代碼
在求和案例vuex版基礎上,要修改的代碼有:
src/components/Count.vue
<template><div><h1>當前求和為:{{sum}}</h1><h3>當前求和放大10倍為:{{bigSum}}</h3><h3>我在{{school}},學習{{subject}}</h3><select v-model.number="n"><option value="1">1</option><option value="2">2</option><option value="3">3</option></select><button @click="increment(n)">+</button><button @click="decrement(n)">-</button><button @click="incrementOdd(n)">當前求和為奇數再加</button><button @click="incrementWait(n)">等一等再加</button></div>
</template><script>import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'export default {name:'Count',data() {return {n:1, //用戶選擇的數字}},computed:{//借助mapState生成計算屬性,從state中讀取數據。(對象寫法)// ...mapState({he:'sum',xuexiao:'school',xueke:'subject'}),//借助mapState生成計算屬性,從state中讀取數據。(數組寫法)...mapState(['sum','school','subject']),/* ******************************************************************** *///借助mapGetters生成計算屬性,從getters中讀取數據。(對象寫法)// ...mapGetters({bigSum:'bigSum'})//借助mapGetters生成計算屬性,從getters中讀取數據。(數組寫法)...mapGetters(['bigSum'])},methods: {//程序員親自寫方法/* increment(){this.$store.commit('JIA',this.n)},decrement(){this.$store.commit('JIAN',this.n)}, *///借助mapMutations生成對應的方法,方法中會調用commit去聯系mutations(對象寫法)...mapMutations({increment:'JIA',decrement:'JIAN'}),//借助mapMutations生成對應的方法,方法中會調用commit去聯系mutations(數組寫法)// ...mapMutations(['JIA','JIAN']),/* ************************************************* *///程序員親自寫方法/* incrementOdd(){this.$store.dispatch('jiaOdd',this.n)},incrementWait(){this.$store.dispatch('jiaWait',this.n)}, *///借助mapActions生成對應的方法,方法中會調用dispatch去聯系actions(對象寫法)...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})//借助mapActions生成對應的方法,方法中會調用dispatch去聯系actions(數組寫法)// ...mapActions(['jiaOdd','jiaWait'])},mounted() {const x = mapState({he:'sum',xuexiao:'school',xueke:'subject'})console.log(x)},}
</script><style lang="css">button{margin-left: 5px;}
</style>
src/store/index.js
//該文件用于創建Vuex中最為核心的store
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//應用Vuex插件
Vue.use(Vuex)//準備actions——用于響應組件中的動作
const actions = {/* jia(context,value){console.log('actions中的jia被調用了')context.commit('JIA',value)},jian(context,value){console.log('actions中的jian被調用了')context.commit('JIAN',value)}, */jiaOdd(context,value){console.log('actions中的jiaOdd被調用了')if(context.state.sum % 2){context.commit('JIA',value)}},jiaWait(context,value){console.log('actions中的jiaWait被調用了')setTimeout(()=>{context.commit('JIA',value)},500)}
}
//準備mutations——用于操作數據(state)
const mutations = {JIA(state,value){console.log('mutations中的JIA被調用了')state.sum += value},JIAN(state,value){console.log('mutations中的JIAN被調用了')state.sum -= value}
}
//準備state——用于存儲數據
const state = {sum:0, //當前的和school:'尚硅谷',subject:'前端'
}
//準備getters——用于將state中的數據進行加工
const getters = {bigSum(state){return state.sum*10}
}//創建并暴露store
export default new Vuex.Store({actions,mutations,state,getters
})
7 多組件共享數據
7.1 細節
看如下需求:sum和persons可以同時共享
細節一
首先是創建Person組件,并在App引入。
緊接著在vuex添加person數據,如下:
緊接著在Person組件引入數據,如下:
- 這里有兩種寫法,但我們使用紅色框的寫法,如果我們使用綠色框的寫法,就避免了一個問題,不利于學習
- 因此在Person組件不使用簡寫方式,而在Count組件使用簡寫方式,這樣利于學習
細節二
現在看看PersonList是怎么進行共享的,先看Count組件,借助mapState讀取。
而Person組件是利用計算屬性讀取的,如下:
sum屬性也同理,可以去看看。
7.2 源代碼
在求和案例vuex版基礎上,要修改的代碼有:
src/components/Count.vue
<template><div><h1>當前求和為:{{sum}}</h1><h3>當前求和放大10倍為:{{bigSum}}</h3><h3>我在{{school}},學習{{subject}}</h3><h3 style="color:red">Person組件的總人數是:{{personList.length}}</h3><select v-model.number="n"><option value="1">1</option><option value="2">2</option><option value="3">3</option></select><button @click="increment(n)">+</button><button @click="decrement(n)">-</button><button @click="incrementOdd(n)">當前求和為奇數再加</button><button @click="incrementWait(n)">等一等再加</button></div>
</template><script>import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'export default {name:'Count',data() {return {n:1, //用戶選擇的數字}},computed:{//借助mapState生成計算屬性,從state中讀取數據。(數組寫法)...mapState(['sum','school','subject','personList']),//借助mapGetters生成計算屬性,從getters中讀取數據。(數組寫法)...mapGetters(['bigSum'])},methods: {//借助mapMutations生成對應的方法,方法中會調用commit去聯系mutations(對象寫法)...mapMutations({increment:'JIA',decrement:'JIAN'}),//借助mapActions生成對應的方法,方法中會調用dispatch去聯系actions(對象寫法)...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})},mounted() {// const x = mapState({he:'sum',xuexiao:'school',xueke:'subject'})// console.log(x)},}
</script><style lang="css">button{margin-left: 5px;}
</style>
src/components/Person.vue
<template><div><h1>人員列表</h1><h3 style="color:red">Count組件求和為:{{sum}}</h3><input type="text" placeholder="請輸入名字" v-model="name"><button @click="add">添加</button><ul><li v-for="p in personList" :key="p.id">{{p.name}}</li></ul></div>
</template><script>import {nanoid} from 'nanoid'export default {name:'Person',data() {return {name:''}},computed:{personList(){return this.$store.state.personList},sum(){return this.$store.state.sum}},methods: {add(){const personObj = {id:nanoid(),name:this.name}this.$store.commit('ADD_PERSON',personObj)this.name = ''}},}
</script>
src/store/index.js
//該文件用于創建Vuex中最為核心的store
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//應用Vuex插件
Vue.use(Vuex)//準備actions——用于響應組件中的動作
const actions = {/* jia(context,value){console.log('actions中的jia被調用了')context.commit('JIA',value)},jian(context,value){console.log('actions中的jian被調用了')context.commit('JIAN',value)}, */jiaOdd(context,value){console.log('actions中的jiaOdd被調用了')if(context.state.sum % 2){context.commit('JIA',value)}},jiaWait(context,value){console.log('actions中的jiaWait被調用了')setTimeout(()=>{context.commit('JIA',value)},500)}
}
//準備mutations——用于操作數據(state)
const mutations = {JIA(state,value){console.log('mutations中的JIA被調用了')state.sum += value},JIAN(state,value){console.log('mutations中的JIAN被調用了')state.sum -= value},ADD_PERSON(state,value){console.log('mutations中的ADD_PERSON被調用了')state.personList.unshift(value)}
}
//準備state——用于存儲數據
const state = {sum:0, //當前的和school:'尚硅谷',subject:'前端',personList:[{id:'001',name:'張三'}]
}
//準備getters——用于將state中的數據進行加工
const getters = {bigSum(state){return state.sum*10}
}//創建并暴露store
export default new Vuex.Store({actions,mutations,state,getters
})
src/App.vue
<template><div><Count/><hr><Person/></div>
</template><script>import Count from './components/Count'import Person from './components/Person'export default {name:'App',components:{Count,Person},mounted() {// console.log('App',this)},}
</script>
8 vuex模塊化 + namespace
8.1 總結
8.2 第一部分
細節問題
細節一 配置store
一開始我們是怎么配置store的,如下:
但現在有個問題,以mutation為例,假設是一個電商系統,我們已經實現了求和模塊、人員模塊,那還要繼續寫訂單模塊,商品模塊等,這樣mutation內容就很多了,很難維護,還有就是所有程序員都操作一個mutation,也容易造成git版本控制沖突。
因此分類整理,相當于分別管理求和的store和人員的store,如下:
緊接著使用配置,如下:
還可以使用簡寫形式,如下:
細節二 Count組件讀取store
由于是初學者,暴露時不使用簡寫形式,便于學習,如下:
mapstate
第一種讀取數據方式如下,會發現比較復雜,如下:
第二種就是利用mapstate的語法,先不管personList,如下:
但這樣寫會報錯,因為沒使用namespace,所以要加上,如下:當添加上namespace后,就可以了。
接下來考慮personList(也要加上namespace)如下:
mapmutation mapaction mapgetters
同理,如下:
8.3 第二部分
細節問題
細節一 Person組件讀取store
之前Person組件不使用簡寫方式,就是因為在這里要學習不使用map方法時如何讀取store。
讀取state
可以看到,用如下的讀取方式:
commit
不用簡寫形式調用Mutations時使用commit,在這里的語法形式如下:
增加一些功能
我們還需要練習getters和dispatch的調用方法,因此在actions和getters上添加一些功能。如下:
getters
在內容添加firstPersonName,如下:
因此需要使用計算屬性,這里的寫法很獨特。
這里有一個方法,就是輸出store看看它究竟是什么寫法,如下:
所以應該這樣寫,如下:
dispatch
然后調用dispatch,和getters類似的寫法,如下:
細節二 store配置管理問題
直接將person和count拆分管理,如下:
然后在index里面引入就行,如下:
細節三 發請求
在person中添加actions,這個api可以返回一個小語錄,這個小語錄作為名字,如下:
緊接著在person組件配置,如下:
8.4 源代碼
在求和案例vuex版基礎上,要修改的代碼有:
src/components/Count.vue
<template><div><h1>當前求和為:{{sum}}</h1><h3>當前求和放大10倍為:{{bigSum}}</h3><h3>我在{{school}},學習{{subject}}</h3><h3 style="color:red">Person組件的總人數是:{{personList.length}}</h3><select v-model.number="n"><option value="1">1</option><option value="2">2</option><option value="3">3</option></select><button @click="increment(n)">+</button><button @click="decrement(n)">-</button><button @click="incrementOdd(n)">當前求和為奇數再加</button><button @click="incrementWait(n)">等一等再加</button></div>
</template><script>import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'export default {name:'Count',data() {return {n:1, //用戶選擇的數字}},computed:{//借助mapState生成計算屬性,從state中讀取數據。(數組寫法)...mapState('countAbout',['sum','school','subject']),...mapState('personAbout',['personList']),//借助mapGetters生成計算屬性,從getters中讀取數據。(數組寫法)...mapGetters('countAbout',['bigSum'])},methods: {//借助mapMutations生成對應的方法,方法中會調用commit去聯系mutations(對象寫法)...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),//借助mapActions生成對應的方法,方法中會調用dispatch去聯系actions(對象寫法)...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})},mounted() {console.log(this.$store)},}
</script><style lang="css">button{margin-left: 5px;}
</style>
src/components/Person.vue
<template><div><h1>人員列表</h1><h3 style="color:red">Count組件求和為:{{sum}}</h3><h3>列表中第一個人的名字是:{{firstPersonName}}</h3><input type="text" placeholder="請輸入名字" v-model="name"><button @click="add">添加</button><button @click="addWang">添加一個姓王的人</button><button @click="addPersonServer">添加一個人,名字隨機</button><ul><li v-for="p in personList" :key="p.id">{{p.name}}</li></ul></div>
</template><script>import {nanoid} from 'nanoid'export default {name:'Person',data() {return {name:''}},computed:{personList(){return this.$store.state.personAbout.personList},sum(){return this.$store.state.countAbout.sum},firstPersonName(){return this.$store.getters['personAbout/firstPersonName']}},methods: {add(){const personObj = {id:nanoid(),name:this.name}this.$store.commit('personAbout/ADD_PERSON',personObj)this.name = ''},addWang(){const personObj = {id:nanoid(),name:this.name}this.$store.dispatch('personAbout/addPersonWang',personObj)this.name = ''},addPersonServer(){this.$store.dispatch('personAbout/addPersonServer')}},}
</script>
src/store/count.js
//求和相關的配置
export default {namespaced:true,actions:{jiaOdd(context,value){console.log('actions中的jiaOdd被調用了')if(context.state.sum % 2){context.commit('JIA',value)}},jiaWait(context,value){console.log('actions中的jiaWait被調用了')setTimeout(()=>{context.commit('JIA',value)},500)}},mutations:{JIA(state,value){console.log('mutations中的JIA被調用了')state.sum += value},JIAN(state,value){console.log('mutations中的JIAN被調用了')state.sum -= value},},state:{sum:0, //當前的和school:'尚硅谷',subject:'前端',},getters:{bigSum(state){return state.sum*10}},
}
src/store/index.js
//該文件用于創建Vuex中最為核心的store
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
import countOptions from './count'
import personOptions from './person'
//應用Vuex插件
Vue.use(Vuex)//創建并暴露store
export default new Vuex.Store({modules:{countAbout:countOptions,personAbout:personOptions}
})
src/store/person.js
//人員管理相關的配置
import axios from 'axios'
import { nanoid } from 'nanoid'
export default {namespaced:true,actions:{addPersonWang(context,value){if(value.name.indexOf('王') === 0){context.commit('ADD_PERSON',value)}else{alert('添加的人必須姓王!')}},addPersonServer(context){axios.get('https://api.uixsj.cn/hitokoto/get?type=social').then(response => {context.commit('ADD_PERSON',{id:nanoid(),name:response.data})},error => {alert(error.message)})}},mutations:{ADD_PERSON(state,value){console.log('mutations中的ADD_PERSON被調用了')state.personList.unshift(value)}},state:{personList:[{id:'001',name:'張三'}]},getters:{firstPersonName(state){return state.personList[0].name}},
}
src/App.vue
<template><div><Count/><hr><Person/></div>
</template><script>import Count from './components/Count'import Person from './components/Person'export default {name:'App',components:{Count,Person},mounted() {// console.log('App',this)},}
</script>