北京建站設計私密瀏覽器免費版
一、vuex的簡介
1、回顧組件之間的通訊
父組件向子組件通訊:通過props實現
子組件向父組件通訊:通過自定義事件($emit)方式來實現
兄弟組件之間的通訊:事件總線($eventBus)、訂閱與發(fā)布方式來實現
跨級組件的通訊:可以通過(provider和inject)方式來實現
2、什么是Vuex
3、使用vuex的好處
-
集中管理共享數據
-
高效實現組件之間數據共享
-
vuex中的數據都是響應式的,能夠實施保持數據與頁面的同步
4、vuex和localStorage的區(qū)別
-
vuex是存儲在內存中,localStroage存儲數據在瀏覽器本地存儲的
-
vuex的數據是瞬時的,localStroage是持久的,是不容易丟失的
-
vuex的數據是響應式的,localStorage中的數據不是響應式的
-
vuex還能完成異步操作(網絡請求的),localStorage僅僅只是一個保存數據和獲取數據
-
vuex中數據按照業(yè)務進行模塊化,localStorage管理數據沒有模塊化
-
vuex直接操作JS的對象無需轉換,localStorage存儲數據要轉成JSON,取數據要將JSON轉成JS對象
-
單頁面應用的程序組件數據共享使用使用狀態(tài)機(vuex),localStorage適合多【頁面數據的共享
5、什么情況下我應該使用 Vuex?
Vuex 可以幫助我們管理共享狀態(tài),并附帶了更多的概念和框架。這需要對短期和長期效益進行權衡。 如果您不打算開發(fā)大型單頁應用,使用 Vuex 可能是繁項幾余的。確實是如此一一如果您的應用夠簡單,您最好不要使用 Vuex,一個簡單的 store 模式就足夠您所需了。但是,如果您需要構建一個中大型單頁應用,您很可能會考慮如何更好地在組件外部管理狀態(tài),Vuex 將會成為自然而然的選擇,引用 Redux的作者 Dan Abramov 的話說就是:
Flux 架構就像眼鏡: 您自會知道什么時候需要它
6、vuex的安裝和基本配置
-
下載vuex的依賴包
npm i vuex@3.6.2
-
在src目錄下創(chuàng)建一個store文件夾
-
在src/store/index.js在此處完成vuex狀態(tài)機倉庫的基本配置
import Vue from 'vue'
import Vuex from 'vuex'
//將vuex以插件的方式設置到Vue中
Vue.use(Vuex)
/*創(chuàng)建倉庫new Vuex.Store(參數)參數是狀態(tài)機配置對象,狀態(tài)機由5大部件組成state:用來管理vuex倉庫(store)中的狀態(tài),它是一個對象mutation:用來操作state的選項,改變數據,它是一個對象actions:異步操作的getters:相當于是狀態(tài)機中的計算屬性modules:模塊化
*/
const store=new Vuex.Store({state:{num:10},mutations:{}
})
//導出store
export default store
-
掛載store到vue中
import Vue from 'vue'
import App from './App.vue'
import store from '@/store'
Vue.config.productionTip = false
?
new Vue({render: h => h(App),store
}).$mount('#app')
二、vuex的基本使用和原理
1、Store核心概念
-
state:用來存儲狀態(tài)的
-
Mutatations:State的數據只能通過Mutations才能改變
-
Actions:用來完成異步操作,比如從后端獲取數據
2、vuex的原理
Vuex的執(zhí)行的流程
-
VueComponents(Vue組件)通過執(zhí)行dispatch向store對象的Actions發(fā)送命令,要求完成異步任務
-
Actions執(zhí)行異步任務,比如向Backend API(后端)發(fā)送請求,從后端獲取到結果
-
Actions通過執(zhí)行commit要求Mutations更改State狀態(tài)機的數據,Mutatations就開始執(zhí)行這個操作
-
Vue Componetents(Vue組件)直接從倉庫中獲取數據
注意點:
-
如果不執(zhí)行異步任務,組件可以直接操作Mutatation來完成倉庫中數據的改變
3、vuex的基本操作
這里以計數器的方式來講解這個案例
3.1、state
-
首先先在store/index.js的state部分定義狀態(tài)機狀態(tài)數據
const store=new Vuex.Store({state:{num:10}
})
-
在組件中獲取這個狀態(tài)數據
組件中如果要獲取store中的state數據的語法
如果要在js代碼部分獲取
this.$store.state.數據名
如果要在template部分獲取
{{$store.state.數據名}}
或者
<div v-bind:屬性="$store.state.數據名"></div>
3.2、mutations
組件中操作狀態(tài)機的數據
如果組件內要更改狀態(tài)機的數據,如果是通過的話,直接通過Mutations的方式去操作
-
在store對象配置對象中添加mutations選項,并定義要操作的方法
const store=new Vuex.Store({state:{num:10},mutations:{INCREMENT(state,payload){state.num++}}
})
參數說明
1) 參數1:state對象
2) 參數2:載荷數據,此數據來源于組件或者actions
-
組件中操作state的數據
this.$store.commit(方法名,傳遞的參數)
export default {methods:{increment(){this.$store.commit('INCREMENT')}}
}
-
如果組件需要給倉庫中傳遞數據,可以通過載荷傳值
const store=new Vuex.Store({state:{num:10},mutations:{INCREMENT_N(state,payload){state.num+=payload}}
})
export default {methods:{incrementN(n){this.$store.commit('INCREMENT_N',3)}}
}
3.3、actions
組件中要調用store倉庫中的actions的語法
this.$store.dispatch('actions的相關方法名',參數)
購物車案例
-
組件
<template><div><h2>購物車列表</h2>{{$store.state.shopcartList}}<table><thead><tr><td>ID</td><td>名稱</td><td>數量</td><td>價格</td><td>小計</td></tr></thead><tbody><tr v-for="(item,index) in $store.state.shopcartList" :key="item._id"><td>{{index+1}}</td><td>{{item.name}}</td><td>{{item.num}}</td><td>{{item.price}}</td><td>{{item.num*item.price}}</td></tr></tbody></table></div>
</template><script>
export default {methods:{getShopcartList(){//調用store倉庫中的actions,讓其執(zhí)行異步操作this.$store.dispatch('getShopcartList_Async')} },created(){this.getShopcartList()}
}
</script><style></style>
-
store
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store=new Vuex.Store({state:{shopcartList:[]},mutations:{getShopcartList_Sync(state,payload){console.log('------2、store中的mutations的getShopcartList_Sync--------------');console.log('payload',payload);state.shopcartList=payload}},//完成異步操作actions:{async getShopcartList_Async(context){console.log('------1、store中的actions的getShopcartListAsync--------------');let result=await Vue.prototype.$api.shopcart.getShopcartData()console.log(result.data);console.log('context',context);context.commit('getShopcartList_Sync',result.data)}}
})
//導出store
export default store
3.4、getters
getters選項中專門是依賴于state數據,產生新的數據,就相當于組件中計算屬性
語法
const store=new Vuex.Store({getters:{getter方法名稱(state){return 處理后的數據}}
})
在組件中調用的語法
this.$store.getters.getter方法名稱
案例:使用getters完成總價計算
const store=new Vuex.Store({getters:{totalPrice:state=>state.shopcartList.filter(item=>item.checked).reduce((prev,cur)=>prev+cur.price*cur.num,0)}
})
組件中方法問
總價:{{$store.getters.totalPrice}}
三、輔助函數
之前我們如果要在組件中訪問狀態(tài)機倉庫中的數據,或者操作狀態(tài)機倉庫的數據,必須通過this.$store這個對象來完成,除了這種方式之外,vuex為我們提供了另外一種組件中訪問或者操作store的方式,這種方式就是輔助函數
輔助函數最重要的思想是將狀態(tài)機中的數據或者方法映射成組件內方法
vuex中提供了以下四種常用方法
-
mapState():這個方法就是將狀態(tài)機倉庫中的state數據映射成組件內數據
-
mapMutatations():將狀態(tài)機倉庫中mutations選項中方法映射組件的方法
-
mapActions():將狀態(tài)機倉庫中actions選項中的方法映射成組件的方法
-
mapGetters():將狀態(tài)機倉庫中getters選項中的方法映射成組件內的計算屬性
1、mapActions的使用
-
導入mapActoins
import {mapActions} from 'vuex'
-
在methods選項中使用擴展運算符來映射倉庫中的actions選項的方法到組件中
export default{methods:{...mapActions(["倉庫中actions選項中的對應的方法名"])}
}
-
直接調用
export default{methods:{...mapActions(["getShopcartList_Async"]),getShopcartList(){this.getShopcartList_Async()}}
}
2、mapState的使用
-
導入mapState
import {mapState} from 'vuex'
-
必須在計算屬性中使用擴展運算符來進行映射
語法
computed:{...mapState(['state中的屬性名'])
}
案例
export default {computed:{...mapState(["shopcartList"])}
}
-
組件中直接使用
{{shopcartList}}
3、mapMutations
-
導入mapMutations
import {mapMutations} from 'vuex'
-
必須在methods中使用擴展運算符的方式將其映射成組件中相關方法
export default {methods:{...mapMutations(["increment_Sync"]),increment(){this.increment_Sync()}}
}
4、mapGetters
-
導入mapGetters
import {mapGetters} from 'vuex'
-
在computed選項中使用擴展運算符將其映射
export default {computed:{...mapGetters(["totalPrice"])},
}
5、別名
如果你映射倉庫中的名字正好和你的組件內的名子沖突了怎么辦
export default{methods:{...mapMutations({"新名稱1":"倉庫中名稱"}),...mapActions({"新名稱1":"倉庫中名稱"})},compouted:{...mapState({"新名稱1":"倉庫中名稱"}),...mapGetters({"新名稱1":"倉庫中名稱"})}
}
總結:actions和mutations是在methods選項中映射的,state和getters是在computed選項中映射的。
四、vuex的模塊化
隨著項目的規(guī)模越來越大,狀態(tài)機的功能越來越多的時候,我們僅僅將所有的功能寫在store/index.js中,這樣會帶來如下的麻煩
-
業(yè)務結構不夠清晰
-
可讀性很差
-
可維護性很差
1、模塊的實現步驟
-
在src/store文件夾下創(chuàng)建modules文件夾
-
在modules文件下創(chuàng)建shopcart.js,內容如下
特別注意:如果要模塊化,必須要在該對象中設置
namespaced:true
export default {namespaced:true,state: {shopcartList: []},mutations: {getShopcartList_Sync(state, payload) {console.log('------2、store中的mutations的getShopcartList_Sync--------------');console.log('payload', payload);state.shopcartList = payload}},actions: {async getShopcartList_Async(context) {console.log('------1、store中的actions的getShopcartListAsync--------------');let result = await Vue.prototype.$api.shopcart.getShopcartData()context.commit('getShopcartList_Sync', result.data)},async checkedProduct_Async(context, payload) {console.log('------1、store中的actions的checkedProduct_Async--------------', payload);let result = await Vue.prototype.$api.shopcart.checkProducts(payload)if (result.code) {//在actions中方法調用actions中的方法context.dispatch('getShopcartList_Async')}},async changeNum_Async(context, payload) {console.log('------1、store中的actions的changeNum_Async--------------', payload);let result = await Vue.prototype.$api.shopcart.changeNum(payload)if (result.code) {context.dispatch('getShopcartList_Async')}}},getters: {totalPrice: state => state.shopcartList.filter(item => item.checked).reduce((prev, cur) => prev + cur.price * cur.num, 0)}
}
-
在store/index文件中引入該模塊
import Vue from 'vue'
import Vuex from 'vuex'
import shopcart from './modules/shopcart'
import counter from './modules/counter'
Vue.use(Vuex)
const store=new Vuex.Store({state:{},mutations:{},actions:{},getters:{},modules:{a:shopcart,b:counter}})
//導出store
export default store
-
在組件中引用
-
原生方式引入
調用actions的方法
this.$store.dispatch("模塊名/actions的相關方法名")
調用getters
{{$store.getters['模塊名/getters的相關名稱']}}
調用state
{{$store.state.模塊名.數據名}}
調用mutations
this.$store.commit('模塊名/mutations的相關方法名')
2、輔助函數訪問模塊化
-
輔助函數訪問模塊化的vuex的步驟
-
導入createNamespacedHelpers
import {createNamespacedHelpers} from 'vuex'
-
通過createNamespacedHelpers()來獲取輔助函數
const {mapActions,mapState,mapGetters}=createNamespacedHelpers('模塊名')
注意:如果在一個組件中要映射多個模塊的輔助函數,就需要為每個模塊的輔助函數取別名,解決命名沖突
const {mapActions:別名,mapState:別名,mapGetters:別名}=createNamespacedHelpers(模塊名)
-
在computed或者methods選項中通過擴展運算符實現映射
methods:{...mapShopcartActions(["getShopcartList_Async"]),...mapCounterMutations(["increment_Sync"]),},computed:{...mapShopcartState(["shopcartList"]),...mapShopcartGetters(["totalPrice"]),...mapCounterState(["num"])}
五、vuex的持久化
vuex中的數據,一旦頁面刷新之后會丟失?怎么處理?【回答】
由于vuex狀態(tài)機中的數據是瞬時的, 保存在內存中的,所以頁面刷新后,數據會丟失,如果要解決這個問題,需要將狀態(tài)機中的數據進行持久化
不是所有的狀態(tài)機的數據都需要持久化的
持久化的思路:持久化就是將vuex狀態(tài)機中的數據保存在localStorage中存一份
1、使用vuex-persistedstate
插件來實現vuex持久化
使用的步驟如下所示
-
安裝
vuex-persistedstate
依賴包
npm i vuex-persistedstate
-
在src/store/index.js中導入
vue-persistedstate
import createPersistedstate from 'vuex-persistedstate'
-
在src/store/index.js在倉庫入口文件中配置插件
const store=new Vuex.Store({//....省略plugins:[createPersistedstate({//存在localstorage中的名字key:'store-num-key',//模塊名.數據名paths:['b.num']})]
})