Vuex的使用指南
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它用于集中管理应用程序的所有组件之间共享的数据,使得状态管理更加方便和可预测。
Vuex 主要包含以下几个核心概念:
State(状态):存储应用程序的状态,即数据。在 Vuex 的 state 中定义数据,可以通过
$store.state
或使用辅助函数mapState
在组件中访问。Getters(计算属性):用于派生状态的函数,在 Vuex 的 getters 中定义。它们可以缓存计算结果,提供组件对状态的访问方式。可以通过
$store.getters
或使用辅助函数mapGetters
在组件中访问。Mutations(突变):用于修改状态的方法,必须是同步函数。在 Vuex 的 mutations 中定义,通过提交 (commit) Mutation 来修改状态。例如:
store.commit('mutationName', payload)
。Actions(动作):用于处理异步操作和提交多个 mutation 的方法。在 Vuex 的 actions 中定义,通过分发 (dispatch) Action 来触发异步操作和提交 Mutation。例如:
store.dispatch('actionName', payload)
。Modules(模块):用于将大型的 Vuex 应用程序划分为更小、更具可维护性的模块。每个模块都有自己的 state、getters、mutations 和 actions。
使用 Vuex 可以帮助我们集中管理应用程序的状态,确保数据的一致性和可追踪性。它适用于中大型的 Vue.js 应用程序,特别是多个组件之间需要共享状态或进行复杂数据交互的场景。
State状态
State 是唯一一个可以直接访问的属性,其他的属性如 Getters、Mutations 和 Actions 都需要通过 State 来获取或修改数据。State 可以被多个组件共享使用,这样就能够保持组件之间的数据同步。
你可以通过在 Vuex store 的 state 属性中定义数据,例如:
const store = new Vuex.Store({
state: {
count: 0, // 整数
price: 9.99, // 浮点数
username: 'John', // 字符串
loggedIn: true, // 布尔值
fruits: ['apple', 'banana', 'orange'], // 数组
user: { // 对象
name: 'John',
age: 30,
email: 'john@example.com'
}
}
});
Getters计算属性
在 Vuex 中,Getters(计算属性)用于派生状态的函数。它们可以对 state 进行基于 state 的计算或数据转换,并可以被组件访问和使用。
计算属性具有缓存机制,只有在依赖的数据发生变化时,计算属性才会重新计算。这样可以避免不必要的重复计算,提高性能。
下面是一个示例:
const store = new Vuex.Store({
state: {
items: [1, 2, 3, 4, 5]
},
getters: {
evenItems: (state) => {
return state.items.filter(item => item % 2 === 0);
},
itemsCount: (state, getters) => {
return getters.evenItems.length;
}
}
});
在上述示例中,定义了两个计算属性:
evenItems
:通过过滤state.items
数组,只保留偶数项。itemsCount
:返回evenItems
数组的长度,即偶数项的数目。
在组件中可以通过 $store.getters
来访问这些计算属性的值:
console.log(this.$store.getters.evenItems); // 输出 [2, 4]
console.log(this.$store.getters.itemsCount); // 输出 2
在模板中使用计算属性:
<template>
<div>
<p>Even Items: {{ $store.getters.evenItems }}</p>
<p>Items Count: {{ $store.getters.itemsCount }}</p>
</div>
</template>
计算属性的值会自动更新,当它所依赖的 state 发生变化时。这使得我们能够轻松地基于 state 的变化来更新组件的显示。
计算属性在处理一些复杂的状态派生和数据转换时非常有用,可以将复杂的计算逻辑封装在计算属性中,让代码更易于理解和维护。
Mutations突变
在 Vuex 中,Mutations(突变)用于修改状态(state)的函数。它们是唯一允许修改 state 的方式,并且必须是同步的操作。
Mutations 接收两个参数:第一个参数是当前的状态(state),第二个参数是负载(payload),即传递给 Mutation 的数据。
下面是一个示例:
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
},
decrement(state, payload) {
state.count -= payload;
}
}
});
在上述示例中,定义了两个 Mutations:
increment
:将state.count
值增加 1。decrement
:从state.count
中减去传入的payload
值。
在组件中可以通过 $store.commit
方法来触发 Mutations:
this.$store.commit('increment');
this.$store.commit('decrement', 5);
每次调用 commit
方法时,对应的 Mutation 函数会被执行,从而修改 state 中的数据。
或者使用 mapMutations 辅助函数:Vuex 提供了 mapMutations
辅助函数,可以将 Mutations 映射到组件的方法中,方便在组件中直接调用 Mutations。
import { mapMutations } from 'vuex';
export default {
// ...
methods: {
...mapMutations(['increment', 'decrement']),
// 或者给 Mutations 起别名
...mapMutations({
add: 'increment'
})
}
}
需要注意的是,Mutations 必须是同步的操作,因此不能在 Mutations 中进行异步操作。如果需要进行异步操作,可以使用 Actions。
Mutations 的作用类似于事件,通过触发 Mutations 来修改 state,以保证状态的变更是可追踪和可预测的。
Actions动作
在 Vuex 中,Actions(动作)用于处理异步操作、封装业务逻辑或者触发多个 Mutations 的函数。Actions 可以包含任意的异步操作,例如发送网络请求、定时器等。Actions 提供了一种将异步操作和状态变更分离的方式。
Actions 接收一个 Context 对象作为参数,其中包含了与 store 实例具有相同方法和属性的对象,例如 state
、commit
、dispatch
、getters
等。通过调用 commit
方法来触发 Mutations,从而修改状态。
下面是一个示例:
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
},
decrement(state, payload) {
state.count -= payload;
}
},
actions: {
incrementAsync(context) {
setTimeout(() => {
context.commit('increment');
}, 1000);
},
decrementAsync(context, payload) {
setTimeout(() => {
context.commit('decrement', payload);
}, 1000);
}
}
});
在上述示例中,定义了两个 Actions:
incrementAsync
:在延迟 1 秒后,调用commit
方法触发increment
Mutations。decrementAsync
:在延迟 1 秒后,调用commit
方法触发decrement
Mutations,并传递payload
参数。
在组件中可以通过 $store.dispatch
方法来触发 Actions:
this.$store.dispatch('incrementAsync');
this.$store.dispatch('decrementAsync', 5);
每次调用 dispatch
方法时,对应的 Action 函数会被执行。Action 函数中可以进行异步操作,并通过调用 commit
方法来触发 Mutations。
需要注意的是,Actions 是可以处理异步操作的,因此可以在 Action 函数中包含任意异步代码。在异步操作完成后,再通过调用 commit
方法来触发 Mutations 进行状态的修改。
类似于 Mutations,也可以使用对象风格的提交、在模块中使用 dispatch
、使用 mapActions
辅助函数等方式来触发 Actions。
Modules模块
在 Vuex 中,Modules(模块)用于将 Vuex 的状态和操作分割为可管理的模块。模块化可以使得大型应用程序的状态管理更加清晰、可维护性更高。
通过模块化,可以将一个大型的 Vuex 应用程序拆分成多个小的模块,每个模块都有自己的 state、mutations、actions 和 getters。
下面是一个示例:
const moduleA = {
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
}
},
actions: {
incrementAsync(context) {
setTimeout(() => {
context.commit('increment');
}, 1000);
}
},
getters: {
doubleCount(state) {
return state.count * 2;
}
}
};
const moduleB = {
// ...
};
const store = new Vuex.Store({
modules: {
moduleA,
moduleB
}
});
在上述示例中,定义了两个模块 moduleA
和 moduleB
,它们分别有自己的 state、mutations、actions 和 getters。然后,在创建 Vuex Store 实例时,通过 modules
选项指定这些模块。
在组件中可以通过 $store.state.moduleA
来访问模块的状态,例如:this.$store.state.moduleA.count
。
类似地,可以使用 $store.commit
、$store.dispatch
和 $store.getters
来触发模块中的 Mutations、Actions 和 Getters。
需要注意的是,在模块中触发 Mutations 和 Actions 时,需要指定模块的路径,例如:this.$store.commit('moduleA/increment')
。
模块化不仅可以帮助组织代码,还能够解决命名冲突、提高可复用性,并且可以将大型应用程序分割为更小的部分进行开发和维护。
案例
定义要共享的属性:
src\store\index.js
import { createStore } from 'vuex'
export default createStore({
state: {
projectId: ''
},
// 定义全局的计算属性,类似于vue组件中的计算属性
getters: {
},
mutations: {
// 必须设置两个参数,第一个参数为state对象,第二个参数为调用该方法时传递的参数
updateProjectId(state, newID){
state.projectId = newID;
},
},
// 定义全局的异步方法,如果有后端接口请求,放在此处定义
actions: {
},
// 模块(当项目结构大且复杂的时候,会对项目中的全局数据分模块管理)
modules: {
}
})
修改要共享的属性
src\views\AllProject.vue
<script>
import { mapState, mapMutations } from 'vuex';
export default {
data() {
return {
// 项目列表
projects: [],
// 定义项目id
id:'',
// 编辑默认弹框
showEditDialog: false,
// 添加项目默认弹框
showAddDialog:false,
// 删除默认弹框
showDelDialog: false,
// 用于接收用户编辑的项目信息
editForm: {
name: '',
leader: '',
},
// 用于接收用户输入的项目信息
addForm:{
name:'',
leader:'',
}
}
},
methods: {
// 更新projectId:方法1
...mapMutations(['updateProjectId']),
goToProjectDetail(id){
console.log('Navigating to Project with ID:', id);
this.updateProjectId(id);
this.$router.push({ name: 'Project' });
}
}
}
</script>
这里使用了 mapMutations
辅助函数来映射 Mutations 到组件的方法中。
mapMutations
是 Vuex 提供的一个辅助函数,用于将指定的 Mutations 映射为组件的方法,使得可以直接在组件中调用这些 Mutations。
在你的示例代码中,通过 ...mapMutations(['updateProjectId'])
将 updateProjectId
Mutation 映射为组件的方法。
然后,在 goToProjectDetail
方法中,首先打印出项目的 ID,然后调用映射的 updateProjectId
方法,将 ID 作为参数传递给该 Mutations。接着使用 $router.push
方法进行导航,跳转到名为 "Project"
的路由。
这样,当 goToProjectDetail
方法被调用时,先触发 Mutations 更新项目 ID 的状态,然后进行路由导航。
需要注意的是,映射的 Mutations 方法会自动和组件的 this.$store.commit
方法绑定,因此可以直接调用,无需手动调用 this.$store.commit
。
或者直接使用this.$store.commit
方法
// 更新projectId:方法2
goToProjectDetail(id) {
console.log('Navigating to Project with ID:', id);
this.$store.commit('updateProjectId', id);
this.$router.push({ name: 'Project' });
}
在 goToProjectDetail
方法中,直接使用 this.$store.commit
方法来触发名为 'updateProjectId'
的 Mutations,并将 id
作为参数传递给该 Mutations。接着使用 $router.push
方法进行路由导航。
这样,当 goToProjectDetail
方法被调用时,先触发 Mutations 更新项目 ID 的状态,然后进行路由导航。
需要注意的是,使用 this.$store.commit
触发 Mutations 时,需要指定该 Mutations 的名称和参数,即 'updateProjectId'
和 id
。
调用要修改的属性
src\views\Project.vue
computed: {
// 方法一:可以使用mapState辅助函数,将state中的全局数据映射到组件中的computed计算属性
...mapState(['projectId'])
},
async created() {
const projectId = this.projectId
console.log('ID:', projectId);
await this.getProjectEnv(projectId);
let options = [];
for (let key in this.env) {
if (typeof this.env[key] === 'object' && this.env[key].hasOwnProperty('name')) {
options.push({
value: this.env[key].id,
label: this.env[key].name,
id:this.env[key].id
});
}
}
this.options = options;
},
使用了 mapState
辅助函数将 Vuex 中的 projectId
映射到组件的计算属性中。
在组件的 computed
中,通过 ...mapState(['projectId'])
将 projectId
映射为组件的计算属性。
或者直接使用this.$store.state.projectId
async created() {
const projectId = this.$store.state.projectId
console.log('ID:', projectId);
await this.getProjectEnv(projectId);
let options = [];
for (let key in this.env) {
if (typeof this.env[key] === 'object' && this.env[key].hasOwnProperty('name')) {
options.push({
value: this.env[key].id,
label: this.env[key].name,
id:this.env[key].id
});
}
}
this.options = options;
},
直接使用 this.$store.state.projectId
获取 Vuex 中的 projectId
。
在 created
生命周期函数中,首先获取 projectId
值并打印出来。
若是在模板中调用属性值
在 Vue 的模板中,可以通过双大括号 {{ }}
或者指令 v-bind
来调用属性值。
如果你想在模板中调用 projectId
的属性值,可以按照以下方式进行修改:
<template>
<div>
<p>Project ID: {{ $store.state.projectId }}</p>
<!-- 或者使用 v-bind 指令 -->
<p>Project ID: <span v-bind:text="$store.state.projectId"></span></p>
</div>
</template>
在上述示例中,使用双大括号 {{ }}
插入 $store.state.projectId
属性的值,并显示在 <p>
元素中。
或者使用使用 mapState
函数
<template>
<div>
<p>Project ID: {{ $store.state.projectId }}</p>
<el-tag>{{ projectId}}</el-tag>
</div>
</template>
<script>
import { mapState} from 'vuex';
export default {
computed: {
// 不推荐
// projectId () {
// return this.store.state.projectId;
// },
// 方法二:可以使用mapState辅助函数,将state中的全局数据映射到组件中的computed计算属性
...mapState(['projectId'])
},
}
</script>
评论