Vuex 是一個專為 Vue.js 應用程序設計的狀態管理模式和庫,它集中管理應用的所有組件的狀態,并以相應的規則保證狀態以一種可預測的方式發生變化。以下是關于 Vuex 的詳細介紹:
1.?核心概念
-
State(狀態)
-
它是 Vuex 中存儲狀態的地方,類似于普通 Vue 組件的
data
選項。所有組件的狀態都存儲在 Vuex 的state
中,組件通過mapState
或直接從 Vuex 中讀取狀態。const store = new Vuex.Store({state: {count: 0} });
Getter(獲取器)
-
類似于 Vue 組件中的計算屬性,用于從
state
中派生出一些狀態。Getter 接收state
作為第一個參數,返回一個計算后的值。const store = new Vuex.Store({state: {todos: [{ id: 1, text: '...', done: true },{ id: 2, text: '...', done: false }]},getters: {doneTodos: state => {return state.todos.filter(todo => todo.done);}} });
Mutation(變異)
-
是修改 Vuex 中狀態的唯一方法。Mutation 是同步函數,接收
state
作為第一個參數,接收額外的參數作為第二個參數。 -
例如:
const store = new Vuex.Store({state: {count: 1},mutations: {increment(state) {state.count++;}} });
Action(動作)
-
類似于 Mutation,但它可以包含異步操作。Action 提交的是 Mutation,而不是直接修改狀態。Action 接收一個上下文對象(包含
state
、commit
等方法)作為第一個參數。 -
例如:
const store = new Vuex.Store({state: {count: 0},mutations: {increment(state) {state.count++;}},actions: {incrementAsync({ commit }) {setTimeout(() => {commit('increment');}, 1000);}} });
Module(模塊)
-
Vuex 允許將狀態分割成模塊(Module)。每個模塊擁有自己的
state
、mutation
、action
和getter
,使得代碼更加模塊化。const moduleA = {state: { ... },mutations: { ... },actions: { ... },getters: { ... } }; const moduleB = {state: { ... },mutations: { ... },actions: { ... } }; const store = new Vuex.Store({modules: {a: moduleA,b: moduleB} });
2.?工作原理
-
Vuex 的核心是
store
,它是一個全局的存儲對象,用于存儲應用的狀態。 -
組件通過
this.$store.state
或mapState
輔助函數來讀取狀態。 -
當需要修改狀態時,組件通過
this.$store.commit
提交一個 Mutation,Mutation 通過同步方式修改狀態。 -
如果需要執行異步操作,組件通過
this.$store.dispatch
觸發一個 Action,Action 內部再提交 Mutation 來修改狀態。 -
Vuex 的狀態更新是響應式的,當狀態發生變化時,Vue 組件會自動更新
-
3.?使用場景
-
Vuex 主要用于管理全局狀態,例如用戶登錄狀態、主題切換、購物車數據等。
-
當應用的狀態變得復雜,多個組件需要共享狀態時,使用 Vuex 可以更好地管理狀態。
4.?優點
-
集中管理狀態:Vuex 將狀態集中管理,避免了組件之間復雜的通信方式。
-
狀態可預測:通過 Mutation 和 Action 的規則,確保狀態的變化是可預測的。
-
方便調試:Vuex 提供了開發者工具,可以方便地查看狀態的變化歷史。
5.實戰?
下面是一個完整的示例,展示如何將 Vuex 的邏輯寫在一個單獨的 JavaScript 文件中,并在 Vue 組件中使用它來修改姓名。
1.?創建 Vuex Store
首先,創建一個名為 store.js
的文件,用于定義 Vuex 的邏輯。
// store.js
import Vue from 'vue';
import Vuex from 'vuex';// 使用 Vuex 插件
Vue.use(Vuex);// 定義狀態
const state = {name: '張三' // 初始姓名
};// 定義 Mutation
const mutations = {// 修改姓名的 MutationsetName(state, newName) {state.name = newName;}
};// 創建 Vuex Store
export default new Vuex.Store({state,mutations
});
2.?在 Vue 應用中引入 Vuex Store
在主文件(如 main.js
或 app.js
)中引入 store.js
,并將其掛載到 Vue 實例中。
// main.js
import Vue from 'vue';
import App from './App.vue';
import store from './store'; // 引入 Vuex Storenew Vue({store, // 將 Vuex Store 掛載到 Vue 實例中render: h => h(App)
}).$mount('#app');
?
3.?在組件中使用 Vuex
在 Vue 組件中,通過 this.$store
來訪問 Vuex 的狀態和提交 Mutation。
示例組件代碼:
<template><div><h1>當前姓名:{{ name }}</h1><input v-model="newName" placeholder="請輸入新姓名" /><button @click="updateName">修改姓名</button></div>
</template><script>
export default {data() {return {newName: '' // 用于雙向綁定輸入框的值};},computed: {// 從 Vuex 中獲取姓名name() {return this.$store.state.name;}},methods: {// 修改姓名的方法updateName() {// 提交 Mutation 來修改姓名this.$store.commit('setName', this.newName);// 清空輸入框this.newName = '';}}
};
</script>
5.?運行效果
-
頁面上顯示當前姓名(初始為“張三”)。
-
用戶可以在輸入框中輸入新的姓名,并點擊“修改姓名”按鈕。
-
點擊按鈕后,姓名會更新為輸入框中的值,并且輸入框清空。
6.?關鍵點總結
-
狀態存儲:姓名存儲在 Vuex 的
state
中。 -
修改狀態:通過提交 Mutation(
setName
)來修改狀態。 -
組件交互:組件通過
this.$store.state
獲取狀態,通過this.$store.commit
提交 Mutation。
?6.mapState
mapState
是 Vuex 中的一個非常有用的輔助函數,它可以幫助我們更方便地在組件中生成與 Vuex 狀態相關的計算屬性,從而避免手動編寫冗長的代碼。使用 mapState
,可以從 Vuex 的 state
中直接提取出狀態,并將其映射為組件的計算屬性。
1.?mapState
?的作用
mapState
的主要作用是簡化從 Vuex 的 state
中提取狀態的過程。它會根據傳入的參數自動生成計算屬性,并確保這些計算屬性能夠響應式地更新。
2.?使用?mapState
?生成多個計算屬性的示例
假設我們有一個 Vuex Store,其中存儲了用戶的名字和年齡。我們希望在組件中使用 mapState
來生成對應的計算屬性,并提供修改名字和年齡的功能。
步驟 1:定義 Vuex Store
在 store.js
文件中定義 Vuex 的狀態、Mutation 和 Action。
// store.js
import Vue from 'vue';
import Vuex from 'vuex';Vue.use(Vuex);const state = {name: '張三', // 初始名字age: 20 // 初始年齡
};const mutations = {setName(state, newName) {state.name = newName;},setAge(state, newAge) {state.age = newAge;}
};export default new Vuex.Store({state,mutations
});
步驟 2:在組件中使用?mapState
在 Vue 組件中,通過 mapState
生成計算屬性,并提供修改名字和年齡的方法。
首先,需要從 vuex
中導入 mapState
:
import { mapState } from 'vuex';
然后,在組件中使用 mapState
來生成計算屬性:
<template><div><h1>用戶信息</h1><p>名字:{{ name }}</p><p>年齡:{{ age }}</p><input v-model="newName" placeholder="請輸入新名字" /><button @click="updateName">修改名字</button><input v-model.number="newAge" placeholder="請輸入新年齡" type="number" /><button @click="updateAge">修改年齡</button></div>
</template><script>
import { mapState } from 'vuex';export default {data() {return {newName: '', // 用于雙向綁定輸入框的新名字newAge: null // 用于雙向綁定輸入框的新年齡};},computed: {// 使用 mapState 生成計算屬性...mapState(['name', 'age'])},methods: {// 修改名字updateName() {this.$store.commit('setName', this.newName);this.newName = ''; // 清空輸入框},// 修改年齡updateAge() {this.$store.commit('setAge', this.newAge);this.newAge = null; // 清空輸入框}}
};
</script>
3.?mapState
?的不同用法
mapState
可以接受多種參數形式,來生成不同的計算屬性:
直接使用數組
如果你只需要將 Vuex 的 state
中的狀態直接映射為組件的計算屬性,可以直接傳遞一個數組:
computed: {...mapState(['name', 'age'])
}
這會生成兩個計算屬性 name
和 age
,它們的內容分別等于 Vuex 的 state.name
和 state.age
。
使用對象映射
如果你需要對生成的計算屬性進行重命名或進行一些額外的處理,可以通過對象映射的方式使用 mapState
:
computed: {...mapState({userName: state => state.name, // 將 Vuex 的 state.name 映射為計算屬性 userNameuserAge: state => state.age // 將 Vuex 的 state.age 映射為計算屬性 userAge})
}
在模板中,你可以直接使用 userName
和 userAge
,而不是 name
和 age
。
完整示例代碼
以下是完整的項目代碼:
store.js
import Vue from 'vue';
import Vuex from 'vuex';Vue.use(Vuex);const state = {name: '張三',age: 20
};const mutations = {setName(state, newName) {state.name = newName;},setAge(state, newAge) {state.age = newAge;}
};export default new Vuex.Store({state,mutations
});
main.js
import Vue from 'vue';
import App from './App.vue';
import store from './store';new Vue({store,render: h => h(App)
}).$mount('#app');
組件(App.vue
)
<template><div><h1>用戶信息</h1><p>名字:{{ name }}</p><p>年齡:{{ age }}</p><input v-model="newName" placeholder="請輸入新名字" /><button @click="updateName">修改名字</button><input v-model.number="newAge" placeholder="請輸入新年齡" type="number" /><button @click="updateAge">修改年齡</button></div>
</template><script>
import { mapState } from 'vuex';export default {data() {return {newName: '',newAge: null};},computed: {// 使用 mapState 生成計算屬性...mapState(['name', 'age'])},methods: {updateName() {this.$store.commit('setName', this.newName);this.newName = '';},updateAge() {this.$store.commit('setAge', this.newAge);this.newAge = null;}}
};
</script>
4.?總結
-
mapState
是一個非常便捷的工具,可以簡化從 Vuex 狀態到組件計算屬性的映射過程。 -
它可以接受數組或對象作為參數,滿足不同的使用需求。
-
使用
mapState
可以讓組件的代碼更加簡潔,也更容易維護。
7.mapMutations
mapMutations
是 Vuex 提供的一個輔助函數,用于簡化在組件中提交 Mutation 的操作。它允許你直接在組件的方法中調用 Mutation,而無需手動使用 this.$store.commit
。這使得代碼更加簡潔,也更容易維護。
1.?mapMutations
?的作用
mapMutations
的主要作用是將 Vuex 的 Mutation 映射為組件方法。它接受一個數組或對象作為參數,根據參數的類型生成對應的組件方法。
2.?使用?mapMutations
?的示例
假設我們有一個 Vuex Store,其中定義了修改名字和年齡的 Mutation。我們希望在組件中使用 mapMutations
來簡化提交這些 Mutation 的操作。
store.js
import Vue from 'vue';
import Vuex from 'vuex';Vue.use(Vuex);const state = {name: '張三',age: 20
};const mutations = {setName(state, newName) {state.name = newName;},setAge(state, newAge) {state.age = newAge;}
};export default new Vuex.Store({state,mutations
});
main.js
import Vue from 'vue';
import App from './App.vue';
import store from './store';new Vue({store,render: h => h(App)
}).$mount('#app');
組件(App.vue
)
<template><div><h1>用戶信息</h1><p>名字:{{ name }}</p><p>年齡:{{ age }}</p><input v-model="newName" placeholder="請輸入新名字" /><button @click="setName(newName)">修改名字</button><input v-model.number="newAge" placeholder="請輸入新年齡" type="number" /><button @click="setAge(newAge)">修改年齡</button></div>
</template><script>
import { mapState, mapMutations } from 'vuex';export default {data() {return {newName: '',newAge: null};},computed: {// 使用 mapState 生成計算屬性...mapState(['name', 'age'])},methods: {// 使用 mapMutations 生成組件方法...mapMutations(['setName', 'setAge'])}
};
</script>
3.?總結
-
mapMutations
是一個非常便捷的工具,可以簡化在組件中提交 Mutation 的操作。 -
它可以接受數組或對象作為參數,滿足不同的使用需求。
-
使用
mapMutations
可以讓組件的代碼更加簡潔,也更容易維護。
8.mapActions?
mapActions
是 Vuex 提供的一個輔助函數,用于簡化在組件中觸發 Action 的操作。它允許你直接在組件的方法中調用 Action,而無需手動使用 this.$store.dispatch
。這使得代碼更加簡潔,也更容易維護。?
1.?mapActions
?的作用
mapActions
的主要作用是將 Vuex 的 Action 映射為組件方法。它接受一個數組或對象作為參數,根據參數的類型生成對應的組件方法。
2.?使用?mapActions
?的示例
假設我們有一個 Vuex Store,其中定義了修改名字和年齡的 Action。我們希望在組件中使用 mapActions
來簡化觸發這些 Action 的操作。
步驟 1:定義 Vuex Store
在 store.js
文件中定義 Vuex 的狀態、Mutation 和 Action。
// store.js
import Vue from 'vue';
import Vuex from 'vuex';Vue.use(Vuex);const state = {name: '張三', // 初始名字age: 20 // 初始年齡
};const mutations = {setName(state, newName) {state.name = newName;},setAge(state, newAge) {state.age = newAge;}
};const actions = {updateName({ commit }, newName) {commit('setName', newName);},updateAge({ commit }, newAge) {commit('setAge', newAge);}
};export default new Vuex.Store({state,mutations,actions
});
步驟 2:在組件中使用?mapActions
在 Vue 組件中,通過 mapActions
生成組件方法,并調用這些方法來觸發 Action。
首先,需要從 vuex
中導入 mapActions
:
import { mapState, mapActions } from 'vuex';
然后,在組件中使用 mapActions
來生成方法:
<template><div><h1>用戶信息</h1><p>名字:{{ name }}</p><p>年齡:{{ age }}</p><input v-model="newName" placeholder="請輸入新名字" /><button @click="updateName(newName)">修改名字</button><input v-model.number="newAge" placeholder="請輸入新年齡" type="number" /><button @click="updateAge(newAge)">修改年齡</button></div>
</template><script>
import { mapState, mapActions } from 'vuex';export default {data() {return {newName: '', // 用于雙向綁定輸入框的新名字newAge: null // 用于雙向綁定輸入框的新年齡};},computed: {// 使用 mapState 生成計算屬性...mapState(['name', 'age'])},methods: {// 使用 mapActions 生成組件方法...mapActions(['updateName', 'updateAge'])}
};
</script>
3.?mapActions
?的不同用法
mapActions
可以接受多種參數形式,來生成不同的組件方法:
直接使用數組
如果你只需要將 Vuex 的 Action 直接映射為組件方法,可以直接傳遞一個數組:
methods: {...mapActions(['updateName', 'updateAge'])
}
這會生成兩個組件方法 updateName
和 updateAge
,它們的內容分別等于 this.$store.dispatch('updateName', ...)
和 this.$store.dispatch('updateAge', ...)
。
使用對象映射
如果你需要對生成的組件方法進行重命名或進行一些額外的處理,可以通過對象映射的方式使用 mapActions
:
methods: {...mapActions({changeName: 'updateName', // 將 Vuex 的 updateName 映射為組件方法 changeNamechangeAge: 'updateAge' // 將 Vuex 的 updateAge 映射為組件方法 changeAge})
}
在模板中,你可以直接使用 changeName
和 changeAge
,而不是 updateName
和 updateAge
。
5.?總結
-
mapActions
是一個非常便捷的工具,可以簡化在組件中觸發 Action 的操作。 -
它可以接受數組或對象作為參數,滿足不同的使用需求。
-
使用
mapActions
可以讓組件的代碼更加簡潔,也更容易維護。
9.dispatch
方法?
dispatch
是 Vuex 中用于觸發 Action 的方法。它允許你在組件或其他地方調用 Vuex 的 Action,從而執行異步操作或一系列的 Mutation。dispatch
是 Vuex 中處理異步邏輯的核心方法,它提供了靈活的方式來管理復雜的狀態更新。
1.?dispatch
?的作用
dispatch
的主要作用是觸發 Vuex 的 Action。Action 可以包含異步操作,如 API 請求、延時操作等。通過 dispatch
,你可以在組件中調用這些 Action,從而間接地修改 Vuex 的狀態。
2.?dispatch
?的基本用法
dispatch
的基本語法如下:
this.$store.dispatch('actionName', payload);
-
actionName
:要觸發的 Action 的名稱。 -
payload
:傳遞給 Action 的參數,可以是任何類型(字符串、數字、對象等)。
3.?示例
假設我們有一個 Vuex Store,其中定義了一個 Action 用于更新用戶信息。我們將在組件中使用 dispatch
來觸發這個 Action。
步驟 1:定義 Vuex Store
在 store.js
文件中定義 Vuex 的狀態、Mutation 和 Action。
// store.js
import Vue from 'vue';
import Vuex from 'vuex';Vue.use(Vuex);const state = {user: {name: '張三',age: 20}
};const mutations = {updateUser(state, userData) {state.user.name = userData.name;state.user.age = userData.age;}
};const actions = {updateUser({ commit }, userData) {// 模擬異步操作setTimeout(() => {commit('updateUser', userData);}, 1000);}
};export default new Vuex.Store({state,mutations,actions
});
步驟 2:在組件中使用?dispatch
在 Vue 組件中,通過 this.$store.dispatch
調用 Action。
<template><div><h1>用戶信息</h1><p>名字:{{ user.name }}</p><p>年齡:{{ user.age }}</p><input v-model="newName" placeholder="請輸入新名字" /><input v-model.number="newAge" placeholder="請輸入新年齡" type="number" /><button @click="updateUser">更新用戶信息</button></div>
</template><script>
export default {data() {return {newName: '',newAge: null};},computed: {user() {return this.$store.state.user;}},methods: {updateUser() {this.$store.dispatch('updateUser', {name: this.newName,age: this.newAge});}}
};
</script>
4.?dispatch
?的高級用法
dispatch
也可以返回一個 Promise,這使得你可以處理 Action 的異步結果。例如,你可以在 Action 中執行異步操作,并在組件中等待這些操作完成。
修改 Action
讓 Action 返回一個 Promise:
const actions = {updateUser({ commit }, userData) {return new Promise((resolve, reject) => {// 模擬異步操作setTimeout(() => {commit('updateUser', userData);resolve();}, 1000);});}
};
在組件中處理 Promise
在組件中等待 Action 完成:
<template><div><h1>用戶信息</h1><p>名字:{{ user.name }}</p><p>年齡:{{ user.age }}</p><input v-model="newName" placeholder="請輸入新名字" /><input v-model.number="newAge" placeholder="請輸入新年齡" type="number" /><button @click="updateUser">更新用戶信息</button></div>
</template><script>
export default {data() {return {newName: '',newAge: null};},computed: {user() {return this.$store.state.user;}},methods: {async updateUser() {try {await this.$store.dispatch('updateUser', {name: this.newName,age: this.newAge});alert('用戶信息更新成功!');} catch (error) {alert('用戶信息更新失敗:' + error.message);}}}
};
</script>
5.?總結
-
dispatch
是 Vuex 中用于觸發 Action 的方法,允許你在組件或其他地方調用 Action。 -
基本用法:
this.$store.dispatch('actionName', payload)
。 -
高級用法:
dispatch
可以返回一個 Promise,使得你可以處理 Action 的異步結果。 -
靈活性:
dispatch
是一個通用方法,可以在任何地方調用,適用于復雜的調用場景。