學習Vue看就夠了(下)
Vue全家桶-Vuex
1.什么是Vuex
Vuex 是一個專為 Vue.js 應用程式開發的狀態管理模式,它采用集中式存盤管理資料,以相應的規則保證狀態以一種可預測的方式發生變化,vuex是Vue官方推薦的集中式狀態管理機制
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-TsaRQ11G-1633609000611)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211007084837130.png)]](https://img.uj5u.com/2021/10/09/271955090838011.png)
2.Vue中存的什么
- 多個組件共享狀態,才存盤在Vuex中
- 某個組件中的私有資料,依舊存盤在Data中
例如:
- 登錄的用戶名需要在首頁,個人中心、結算頁面使用,用戶名存在vuex中
- 文章詳情的資料,只有在文章詳情頁查看,在自身data中宣告
3.為什么要學vuex
程式頁面多, 資料變數多
- 不同組件資料保持同步
- 資料的修改都是可追蹤
資料同步、集中管理

4.vuex五個核心概念是?
| 配置項 | 含義 | 注意 |
|---|---|---|
| state | 單一狀態樹 | 類似data |
| mutations | 資料管家(同步) | 唯一修改state地方 |
| actions | 異步請求 | 要改state需要提交給mutations |
| getters | vuex計算屬性 | 類似computed |
| modules | 模塊拆分 |
圖示關系
單一定義store物件, 里面5個配置項, 在任意組件可以使用

5.vuex實體
初始化新的工程 vuex-demo
vue create vuex-demo
清慷訓迎界面
并設定三個組件,目錄如下:
|-components
|---AddItem.vue
|---SubItem.vue
|-App.vue
App.vue
復制標簽和樣式, 引入AddItem和SubItem2個子組件顯示
<template>
<div id="app">
<h1>根組件</h1>
<span>庫存總數:</span>
<input type="text">
<div style="border:1px solid black; width: 300px;">
<AddItem></AddItem>
</div>
<hr>
<div style="border:1px solid black; width: 300px;">
<SubItem></SubItem>
</div>
</div>
</template>
<script>
import AddItem from '@/components/AddItem'
import SubItem from '@/components/SubItem'
export default {
components: {
AddItem,
SubItem
}
}
</script>
<style>
#app {
width: 300px;
margin: 20px auto;
border:1px solid #ccc;
padding:4px;
}
</style>
AddItem.vue
<template>
<div>
<h3>AddItem組件</h3>
<p>已知庫存數: 0</p>
<button>庫存+1</button>
</div>
</template>
<script>
export default {
}
</script>
SubItem.vue
<template>
<div>
<h3>SubItem組件</h3>
<p>已知庫存數: 0</p>
<button>庫存-1</button>
</div>
</template>
<script>
export default {
}
</script>
創建store倉庫
和路由模塊router/index.js類似,維護專案目錄的整潔,新建src/store/index.js檔案
- 下載vuex
yarn add vuex
npm install vuex
- 在store/index.js 創建定義匯出store
// 目標: 創建store倉庫物件
// 1. 下載vuex: 終端命令(yarn add vuex)
// 2. 引入vuex
import Vue from 'vue'
import Vuex from 'vuex'
// 3. 注冊
Vue.use(Vuex)
// 4. 實體化store物件
const store = new Vuex.Store({})
// 5. 匯出store物件
export default store
- main.js - 匯入注入到Vue中
import Vue from 'vue'
import App from './App.vue'
import store from '@/store' // 匯入store物件
Vue.config.productionTip = false
new Vue({
// 6. 注入到Vue實體中(確保組件this.$store使用)
store,
render: h => h(App),
}).$mount('#app')
6.vuex-state資料源
state是唯一的公共資料源,統一存盤資料
定義state
在store/index.js定義state語法:
/*
const store = new Vuex.Store({
state: {
變數名: 初始值
}
})
*/
具體代碼:
const store = new Vuex.Store({
state: {
count: 100 // 庫存
}
})
使用state種方式
方式1: 組件內 - 直接使用:語法
this.$store.state.變數名
方式2: 組件內 - 映射使用 (推薦):語法
// 1. 拿到mapState輔助函式
import { mapState } from 'vuex'
export default {
computed: {
// 2. 把state里變數映射到計算屬性中
...mapState(['state里的變數名'])
}
}
AddItem直接用
<template>
<div>
<h3>AddItem組件</h3>
<p>已知庫存數: {{ $store.state.count }}</p>
<button>庫存+1</button>
</div>
</template>
App.vue直接用
計算屬性count, 和輸入框的v-model雙向系結
<input type="text" v-model="count">
<script>
export default {
computed: {
count: {
set(){},
get(){
return this.$store.state.count
}
}
}
}
</script>
SubItem映射用
<template>
<div>
<h3>SubItem組件</h3>
<p>已知庫存數: {{ count }}</p>
<button>庫存-1</button>
</div>
</template>
<script>
// 需求1: 映射state到計算屬性
// 1. 拿到輔助函式 mapState
// 2. 在computed內, ...mapState(['state變數名'])
// 3. 當計算屬性使用
import { mapState } from 'vuex'
// let r = mapState(['count']) // 提取store里的state叫count的變數
// console.log(r); // 回傳值: {count: 函式體(return state里count的值)}
export default {
computed: {
// 映射count, 得到物件展開, 合并到計算屬性中
...mapState(['count'])
},
}
</script>
整個程序的示意圖如下
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-D6zinR80-1633609000617)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211007092400673.png)]](https://img.uj5u.com/2021/10/09/271955090838014.png)
注意:
state是回應式的, 只要state值變化, 頁面上使用的地方會自動更新同步
7.vuex-mutations定義-同步修改
mutations類似資料管家, 操作state里的資料
在store/index.js定義mutations
語法:
/*
const store = new Vuex.Store({
mutations: {
函式名 (state, 可選值) {
// 同步修改state值代碼
}
}
})
*/
具體代碼
const store = new Vuex.Store({
state: {
count: 100 // 庫存
},
mutations: {
addCount (state, value) { // 負責增加庫存的管家
state.count += value
},
subCount (state, value) { // 負責減少庫存的管家
state.count -= value
},
setCount (state, value) { // 負責直接修改庫存的管家
state.count = value;
}
}
})
注意
- mutations是唯一能修改state的地方, 確保除錯工具可以追蹤變化
- mutations函式內, 只能寫同步代碼, 除錯工具可追蹤變化程序
- 因為除錯工具要立刻產生一次記錄, 所以必須是同步的
使用mutations的2種方式
方式1: 組件內 - 直接使用
語法:
this.$store.commit("mutations里的函式名", 具體值)
方式2: 組件內 - 映射使用
語法:
// 1. 拿到mapMutations輔助函式
import { mapMutations } from 'vuex'
export default {
methods: {
// 2. 把mutations里方法映射到原地
...mapMutations(['mutations里的函式名'])
}
}
直接使用
<button @click="addFn">庫存+1</button>
<script>
export default {
methods: {
addFn(){
this.$store.commit('addCount', 1)
}
}
}
</script>
在App.vue直接用
- 觸發計算屬性的set方法
- 提交mutations傳入值
<span>庫存總數: </span>
<input type="text" v-model="count">
<script>
export default {
computed: {
count: {
set(val){
this.$store.commit('setCount', val) // 把表單值提交給store下的mutations
},
get(){
return this.$store.state.count
}
}
}
}
</script>
SubItem映射用
- 點擊事件
- 映射mutations的方法
- 呼叫mutations方法傳值
<button @click="subFn">庫存-1</button>
<script>
// 需求2: 映射mutations到方法里
// 1. 拿到輔助函式 mapMutations
// 2. 在methods內, ...mapMutations(['mutations函式名'])
// 3. 當普通方法使用
import { mapMutations } from 'vuex'
export default {
methods: {
...mapMutations(['subCount']),
subFn(){
this.subCount(1)
}
}
}
</script>
注意
mutations函式上, 只能接收一個引數值, 如果傳對個, 請傳一個物件
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-b83jbQol-1633609000619)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211007093204064.png)]](https://img.uj5u.com/2021/10/09/271955090838015.png)
8.vuex-actions定義-異步修改
定義actions
在store/index.js定義actions
語法:
/*
const store = new Vuex.Store({
actions: {
函式名 (store, 可選值) {
// 異步代碼, 把結果commit給mutations給state賦值
}
}
})
*/
具體代碼:
const store = new Vuex.Store({
// ...省略state和mutations此處
actions: {
asyncAddCount(store, num){
setTimeout(() => { // 1秒后, 異步提交給add的mutations
store.commit('addCount', num)
}, 1000)
},
asyncSubCount(store, num) {
setTimeout(() => { // 1秒后, 異步提交給sub的mutations
store.commit('subCount', num)
}, 1000)
}
}
})
使用actions的2種方式
方式1: 組件內 - 直接使用
語法:
this.$store.dispatch('actions函式名', 具體值)
方式2: 組件內 - 映射使用
語法:
// 1. 拿到mapActions輔助函式
import { mapActions } from 'vuex'
export default {
methods: {
// 2. 把actions里方法映射到原地
...mapActions(['actions里的函式名'])
}
}
AddItem直接用
- 點擊事件
- dispatch觸發action
<button @click="asyncAddFn">延遲1秒, 庫存+5</button>
<script>
export default {
methods: {
asyncAddFn(){
this.$store.dispatch('asyncAddCount', 5)
}
}
}
</script>
SubItem映射用
- 點擊事件
- 映射actions的方法
- 呼叫actions的方法傳值
<button @click="asyncSubFn">延遲1秒, 庫存-5</button>
<script>
// 需求3: 映射actions到方法里
// 1. 拿到輔助函式 mapActions
// 2. 在methods內, ...mapActions(['actions函式名'])
// 3. 當普通方法使用
import { mapActions } from 'vuex'
export default {
methods: {
...mapActions(['asyncSubCount']),
asyncSubFn(){
this.asyncSubCount(5)
}
}
}
</script>
視圖組件, state, mutations, actions的關系是?
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-mDvNqbBV-1633609000621)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211007193136853.png)]](https://img.uj5u.com/2021/10/09/271955090838016.png)
9.vuex-getters定義-計算屬性
概念:vuex身上的全域狀態-屬于全域計算屬性, 類似于computed,getters 依賴于 state中原始資料的變化,并回傳計算后的新資料
-
定義getters
-
在store/index.js定義getters
語法:
/* const store = new Vuex.Store({ getters: { 計算屬性名 (state) { return 值給計算屬性 } } }) */ -
-
具體的代碼
const store = new Vuex.Store({ // ...省略其他 getters: { allCount(state) { return state.goodsList.reduce((sum, obj) => { if (obj.goods_state === true) { // 選中商品才累加數量 sum += obj.goods_count; } return sum; }, 0) }, allPrice(state) { return state.goodsList.reduce((sum, obj) => { if (obj.goods_state) { sum += obj.goods_count * obj.goods_price } return sum; }, 0) } } }) -
使用getters的2種方式
-
方式1: 組件內 - 直接使用
語法:
this.$store.getters.計算屬性名-
方式2: 組件內 - 映射使用
語法:
// 1. 拿到mapGetters輔助函式 import { mapGetters } from 'vuex' export default { computed: { // 2. 把getters里屬性映射到原地 ...mapGetters(['getters里的計算屬性名']) } } -
在APP.vue里面使用
- 使用2種方式給計算屬性值
<script>
import { mapGetters } from 'vuex'
export default {
computed: {
allCount(){
return this.$store.getters.allCount;
},
...mapGetters(['allPrice'])
}
}
</script>
10.vuex-modules定義
-
為何分模塊
由于使用的是單一狀態樹,應用的所有狀態會集中到一個比較大的物件,
當應用變的非常復雜的時候,store物件就有可能變得相當臃腫!!!,為了解決這個問題,Vuex允許我們**將store分割成模塊**(module),每個模塊擁有自己的state,mutation、action、getter、甚至是嵌套子模塊 -
代碼上的對比
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-uIFDlGx1-1633609000622)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211007194520441.png)]](https://img.uj5u.com/2021/10/09/271955090838017.png)
- 創建modules模塊物件
- 新建store/modules/user.js
- 新建store/modules/cart.js
- 語法,物件里面包含5個核心,只有state變成函式的形式
user.js - 用戶模塊物件
// 用戶模塊物件
const userModule = {
state(){
return {
name: "",
age: 0,
sex: ''
}
},
mutations: {},
actions: {},
getters: {}
}
export default userModule
cart.js - 購物車模塊物件
// 購物車模塊物件
import axios from 'axios'
const cartModule = {
state() {
return {
goodsList: []
}
},
mutations: {
setGoodsList(state, newList) {
state.goodsList = newList
}
},
actions: {
async asyncGetGoodsList(store) {
const url = `https://www.escook.cn/api/cart`
// 發送異步請求
const res = await axios({ url: url });
store.commit('setGoodsList', res.data.list) // 提交mutation修改state中的資料
}
},
getters: {
allCount(state) {
return state.goodsList.reduce((sum, obj) => {
if (obj.goods_state === true) { // 選中商品才累加數量
sum += obj.goods_count;
}
return sum;
}, 0)
},
allPrice(state) {
return state.goodsList.reduce((sum, obj) => {
if (obj.goods_state) {
sum += obj.goods_count * obj.goods_price
}
return sum;
}, 0)
}
}
}
export default cartModule
定義模塊(module)
在store/index.js中引入這兩個組件,注冊一下
import Vue from 'vue'
import Vuex from 'vuex'
import cartModule from './modules/cart'
import userModule from './modules/user'
Vue.use(Vuex)
const store = new Vuex.Store({
//注冊
modules: {
user: userModule,
cart: cartModule
}
})
export default store
注意:只要使用了模塊,state取值的方式會發生變化
state使用方式修改
方式1: 組件內 - 直接使用
原語法:
this.$store.state.變數名
分模塊后的語法:
this.$store.state.模塊名.變數名
方式2 組件內映射的方式使用
原語法:
...mapState(['state里變數名'])
...mapState({'變數名': "state里變數名"})
分模塊后語法:
...mapState({
'變數名': state => state.模塊名.變數名
})
分模塊-命名空間開啟
命名空間開啟是為了:防止多個模塊之間,mutations/actions/getters的名字沖突
開啟命名空間
在模塊物件內設定namespaced: true
const moduleShopCar = {
//開啟命名空間,防止多個模塊之間,mutations/actions/getters的名字發生沖突
namespaced: true,
state () {},
mutations: {},
actions: {},
getters: {},
modules: {}
}
state使用方式修改
- 直接使用無變化: this.$store.state.模塊名.變數名
- 輔助函式需要遵守格式
...mapState("模塊名", ['state變數名'])
mutations使用方式修改
方式1: 組件內 - 直接使用
- 原語法:
this.$store.commit("mutations里的函式名", 具體值)
- 開命名空間后語法:
this.$store.commit("模塊名/mutations里的函式名", 具體值)
方式2: 組件內 - 映射使用
- 原語法:
...mapMutations(['mutations里方法名'])
- 開命名空間后語法:
...mapMutations("模塊名", ['mutations里方法名'])
actions使用方式修改
-
方式1: 組件內 - 直接使用
-
原語法:
this.$store.dispatch("actions里的函式名", 具體值) -
開命名空間后語法:
this.$store.dispatch("模塊名/actions里的函式名", 具體值)
-
-
方式2: 組件內 - 映射使用
-
原語法:
...mapActions(['actions里方法名']) -
開命名空間后語法:
...mapActions("模塊名", ['actions里方法名'])
-
getters使用方式修改
-
方式1: 組件內 - 直接使用
-
原語法:
this.$store.getters.計算屬性名 -
開命名空間后語法:
this.$store.getters['模塊名/計算屬性名']
-
-
方式2: 組件內 - 映射使用
-
原語法:
...mapGetters(['getters里計算屬性名']) -
開命名空間后語法:
...mapGetters("模塊名", ['getters里計算屬性名'])
-
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/306442.html
標籤:其他
上一篇:Echarts空氣質量地圖效果
