Vuex 官网🔗: Vuex 是一个专为 Vue.js 应用程序设计的状态管理库
,它提供了一种集中式管理
应用中的状态;
状态管理模式: 它让组件的状态(数据)
,管理变得集中、有序,便于在整个应用中,共享和维护数据;
集中式存储: 它将应用的所有组件状态(数据)
,集中到一个单一的存储对象中,使得统一管理;
在复杂的Vue应用中: 多个组件常常需要共享状态(数据)
,直接传递props、使用事件机制会使程序变得 复杂且难以维护;
Vuex 是一个插件,可以帮我们管理 vue 通用的数据实现:多组件数据共享,多组件共同修改数据信息;
Vuex 应用场景: 跨组件共享状态 比如用户信息、购物车内容等,Vuex 提供了一个中心化的存储,
使得这些数据可以在任何组件中访问和更新,而无需通过复杂的父子组件传递或事件监听;
(官方)注意: 不是所有的场景都适用于Vuex
,只有在必要的时候才使用Vuex
使用了Vuex之后,会附加更多的框架中的概念进来,增加了项目的复杂度,(数据的操作更便捷,数据的流动更清晰)
vue create vuex-demo
勾选:css预处理器、正常情况还需要勾选 vuex
,router
此处演示个人搭建环境;
vuex是一个独立存在的插件,如果脚手架初始化没有选 vuex,就需要额外安装,注意版本兼容:vue2\3\3原则;
yarn add vuex@3 #或 npm i vuex@3
为了维护项目目录的整洁,在src目录下新建一个store
目录其下放置一个index.js
📄
Vuex的store是一个集中存储应用所有组件共享状态的地方,所有,共享的数据都要统一放到 Store 中的 State 中存储;
它类似于一个全局数据仓库,在组件中访问状态: 通过this.$store
访问store
中的数据、触发mutations
、调用actions
等
// 导入 vue、vuex
import Vue from 'vue'
import Vuex from 'vuex'
// 启用 Vuex 插件
Vue.use(Vuex)
// 创建仓库 store 状态,即数据:
// 类似于vue组件中的data、data 是组件自己的数据;
// state 中的数据整个vue项目的组件都能访问到;
const store = new Vuex.Store({
state: {
count: 100
}
})
// 导出仓库 store
export default store
在Vue应用中引入Store:main.js
中导入store,并将其添加到Vue实例中作为选项;
import Vue from 'vue'
import App from './App.vue'
import store from './store'
Vue.config.productionTip = false
new Vue({
//挂载至Vue实例
render: h => h(App),
store
}).$mount('#app')
App.js: 通过this.$store
访问store
中的数据,此数据可以在任何组件中进行访问;
<template>
<div id="app">
<p>store公共仓库获取数据: {{ $store.state.count }}</p>
</div>
</template>
<script>
export default { name: 'App', }
</script>
<style></style>
在Vuex中,State是状态管理的核心组成部分之一,它扮演着应用单一数据源
的角色:
单一数据源: State
是Vuex store
中存储的所有组件共享的数据状态,官方定义: 将数据称为 State状态;
它提供了一个全局的、集中式的存储空间,使得任何组件都能访问到这些状态,从而实现状态的统一管理;
响应式:Vue的响应式系统使得当state
中的数据发生变化时,所有依赖于这些数据的Vue组件能够自动更新;
这意味着你可以在组件中直接使用store中的状态,并且当状态改变时,视图会自动响应这些变化;
案例: 在App.JS
主组件中引入,多个组件同时获取:Vuex
的数据进行展示; Son1.vue\Son2.vue
<template>
<div class="box">
<h2>Son1 子组件</h2>
从vuex中获取的值: <label>{{ $store.state.count }}</label>
</div>
</template>
<script></script>
<style></style>
获取Vuex数据: 通过$store
访问的语法,可以直接在组件
、组件脚本.JS
、src/main.JS
快速访问;
//Vue模板中直接使用
{{ $store.state.xxx }}
//Vue模板.js文件中获取
this.$store.state.xxx
//src/main.JS 主文件中获取
import store from './store'
store.state.xxx;
mapState辅助函数:为了简化组件中对state
的访问,
Vuex
提供了mapState辅助函数
,可以将store
中的状态映射为组件的计算属性;
正常情况下,我们在组件中访问数据通过: {{ store.state.xxx }} 、this.store.state.xxx、...
实际使用过程有点麻烦,mapState函数,可以直接将 state-store状态数据
映射为一个计算属性直接访问: {{ xxx }}
mapState(['xxx','xxx']);
可以获取对应 store状态数据
,赋值给 计算属性,方便快速访问;<template>
<div id="app">
<h1>
根组件
- {{ title }}
<!-- - {{ $store.state.title }} -->
</h1>
<p>store公共仓库获取数据: {{ count }}</p> <!-- {{ $store.state.count }} -->
<hr>
<Son1></Son1>
<Son2></Son2>
</div>
</template>
<script>
import Son1 from './components/Son1.vue';
import Son2 from './components/Son2.vue';
import { mapState } from 'vuex'; //通过ES6 语法对象解构直接获取mapState;
export default {
name: 'App',
components: { Son1, Son2, },
created(){
//created初始化钩子函数\查看$store\mapState对象属性;
console.log("组件脚本中访问Vuex: "+this.$store.state.title);
console.log("mapState['title']: "+mapState(['title']));
console.log("mapState 对象属性: "+mapState);
},
//计算属性
computed:{
...mapState(['title','count']), //通过ES6 语法对象展开运算符,导出的状态映射给计算属性;
//如果没有 ...mapState(['title','count']), 为了方便页面获取 $store.state 状态数据,通常需要自定义函数;
diytitle(){ return this.$store.state.title; } //方便组件使用,$store.state 状态数据,当然计算函数支持更多自定义操作;
}
}
</script>
<style></style>
禁止直接修改:
直接修改store
中的state状态数据
是被严格禁止的,
任何状态的改变都必须通过提交mutation
来完成,以确保状态变更的可追踪性和一致性;
模块化状态: 在大型应用中,状态可能会非常复杂,因此可以将state
分割到不同的模块中,
每个模块拥有自己的state
,这有助于管理复杂的状态结构,后面介绍:Vuex模块化
在Vuex中,mutations
是用于改变状态唯一合法方式,它遵循严格同步规则,确保状态变更的可预测性和调试的便利性
Vuex 遵循单向数据流,组件中不能直接修改仓库的数据: 但, 默认情况下并不会报错;
👇👇
<!-- Vuex store、state状态数据可以直接修改 -->
<template>
<div class="box">
<h2>Son1 子组件</h2>
从vuex中获取的值: <label>{{ $store.state.count }}</label>
<button @click="$store.state.count++">值 + 1</button> <!-- 错误写法但不会报错; -->
<button @click="addcount2()">值 + 2</button> <!-- 错误写法但不会报错; -->
</div>
</template>
<script>
export default {
//直接修改Vuex store、state状态数据
methods:{ addcount2(){ this.$store.state.count+=2; } }
}
</script>
Vuex 的严格模式是一种开发时的辅助工具,它强制所有的状态变更必须通过 mutation 来进行:
这有助于维护状态的一致性,避免了状态的隐式修改,使得应用的行为更加可预测;
启用方式:在创建 Vuex store
实例时,通过设置 strict: true
启用严格模式:
const store = new Vuex.Store({
strict: true
// ...store配置
});
为什么可以直接修改,还要使用mutations:
Mutations是Vuex中实现状态变更的核心机制,它确保了状态的改变是有序的、可追踪的,并且遵循一定的规范:
mutations
中,使得这部分代码更加模块化和易于测试;
Vue DevTools
时,可以清晰地看到每次mutation
对状态的影响;
使用:mutatios 修改state状态:
state(必须、状态数据)
、payload(可选、传递参数)
this.$store.commit('处理函数名', 传递参数);
在Vuex的store
配置中,定义mutations
对象,其中: 键 =是=>事件类型(通常是大写命名)
、值=是=>处理函数
// 创建仓库 store 状态,即数据:
// 类似于vue组件中的data、data 是组件自己的数据;
// state 中的数据整个vue项目的组件都能访问到;
const store = new Vuex.Store({
//开启严格模式
strict: true,
state: {
count: 10,
title: "大标题1",
},
//mutations对象其中键是事件类型通常是大写命名)、值是处理函数;
mutations:{
//state: 表示当前Vuex中的state状态数据库,用来获取其操作数据;
ADD_COUNT(state){ state.count++; },
//带参传递数据: 参数只能一个,如果有多个参数,包装成一个{对象}\[数组] 传递;
ADD_COUNTX(state,payload){ state.count+=payload }
}
})
在组件中通过,调用、提交:mutation处理函数,形式完成,状态修改: Son2.vue
<template>
<div class="box">
<h2>Son2 子组件</h2>
从vuex中获取的值: <label>{{ $store.state.count }}</label>
<button @click="addCount()">值 + 1</button> <!-- mutatios修改state -->
<button @click="addCountx(3)">值 + 3</button> <!-- mutatios带 参? 修改state -->
<button @click="addCountx(5)">值 + 5</button> <!-- mutatios带 参? 修改state -->
</div>
</template>
<script>
export default {
methods:{
//无参自动+1
addCount(){ this.$store.commit('ADD_COUNT'); },
addCountx(x){ this.$store.commit('ADD_COUNTX',x); } //自定义传参添加数值;
}
}
</script>
mapMutations
是Vuex
提供的一个辅助函数,它简化了在Vue
组件中提交mutation
的过程:
这个辅助函数允许:store
中的mutations
映射到组件的methods
中,
使得你可以直接在组件的方法中调用这些mutation
,
而不需要手动使用this.$store.commit
;
Son3.vue: 和mapState
用法类型,mapState
针对状态数据\使用计算属性进行优化,
mapMutations
针对状态数据修改操作\使用method
函数进行优化,自动将事件函数名,匹配生成一个method函数
<template>
<div class="box">
<h2>Son3 子组件</h2>
从vuex中获取的值: <label>{{ $store.state.count }}</label>
<button @click="addCount()">值 + 1</button> <!-- mutatios修改state -->
<button @click="addCountx(10)">值 + 10</button> <!-- mutatios带 参? 修改state -->
<button @click="ADD_COUNTX(-10)">值 - 10</button> <!-- mutatios带 参? 修改state -->
</div>
</template>
<script>
import { mapMutations } from 'vuex'; //通过ES6 语法对象解构直接获取mapMutations;
export default {
methods:{
//方式一: 直接映射名为increment的mutation
...mapMutations(['ADD_COUNT','ADD_COUNTX']),
//方式二: 使用对象形式来映射并重命名
...mapMutations({
'addCount' : "ADD_COUNT", //组件方法名: store中的mutation名
'addCountx' : "ADD_COUNTX",
}),
}
}
</script>
注意: Vuex中mutations中不能写异步代码,如果有异步的ajax请求,应该放置在actions中;
在Vuex中,actions和mutations类似,是用于处理异步操作的关键部分:
它们允许你执行异步逻辑,比如API调用,并且最终通过触发一个或多个mutations
来改变状态;
在Vuex的store
配置中,定义actions
对象: 虽然actions
可以执行异步逻辑,但它们不能直接修改state
相反,它们通过调用context.commit
来触发mutation
,从而间接改变状态,也就是说:actions依赖mutation操作state;
// 创建仓库 store 状态,即数据:
// 类似于vue组件中的data、data 是组件自己的数据;
// state 中的数据整个vue项目的组件都能访问到;
const store = new Vuex.Store({
//开启严格模式
strict: true,
state: {
count: 10,
title: "大标题1",
},
//mutations对象其中键是事件类型通常是大写命名)、值是处理函数;
mutations:{
//state: 表示当前Vuex中的state状态数据库,用来获取其操作数据;
ADD_COUNT(state){ state.count++; },
//带参传递数据: 参数只能一个,如果有多个参数,包装成一个{对象}\[数组] 传递;
ADD_COUNTX(state,payload){ state.count+=payload }
},
//actions 处理异步: 注意,不能直接操作state 操作state 还是需要context.commit('mutation名','传参');
actions:{
//actions 接收参数: context对象提供了对store的访问、payload作为参数对象
changeCountAction(context,num){
// 这里是setTimeout模拟异步,以后大部分场景是发请求
setTimeout(() => { context.commit('ADD_COUNTX', num) }, 1000)
}
}
})
在Vue组件中,你可以通过this.$store.dispatch('actions名','参数对象')
来触发action
;
<template>
<div class="box">
<h2>Son3 子组件</h2>
从vuex中获取的值: <label>{{ $store.state.count }}</label>
<button @click="addCount()">值 + 1</button> <!-- mutatios修改state -->
<button @click="addCountx(10)">值 + 10</button> <!-- mutatios带 参? 修改state -->
<button @click="ADD_COUNTX(-10)">值 - 10</button> <!-- mutatios带 参? 修改state -->
<button @click="changeCountAction(888)">1秒后改成888</button> <!-- actions 异步操作state -->
</div>
</template>
<script>
import { mapMutations } from 'vuex'; //通过ES6 语法对象解构直接获取mapMutations;
export default {
methods:{
//方式一: 直接映射名为increment的mutation
//方式二: 使用对象形式来映射并重命名 ....省略....
//在Vue组件中,你可以通过this.$store.dispatch来触发action:
async changeCountAction(x){
await this.$store.dispatch('changeCountAction',x);
},
}
}
</script>
mapActions
是Vuex提供的一个辅助函数,和mapMutations
类似,
它允许你将store
中的actions
便捷地映射到Vue
组件的methods
中,从而简化组件内调用这些异步操作的流程;
//通过ES6 语法对象解构直接获取mapMutations...
import { mapMutations,mapActions } from 'vuex';
export default {
methods:{
//mapActions 使用: 和mapMutations类似
...mapActions(['changeCountAction']),
...mapActions({
"divChangeCountAction": "changeCountAction"
}),
}
}
Vuex
中的 getters
是用来从 store
的状态state
中派生出一些状态的计算属性: 类似于组件中的 computed
计算属性;
getters
用于对 state
进行计算和过滤,生成新的数据视图;
有时我们还需要从state
中派生出一些状态,这些状态是依赖state
的,此时会用到getters
getters
的值会被缓存,只有当其依赖的 state
或其他 getters
发生变化时,才会重新计算;
getters
可以通过 store.getters
访问,或者在 Vue
组件中通过 this.$store.getters
访问;
这使得多个组件可以共享这些计算后的数据,避免代码重复
例如: state
中定义了list
的数组,组件中,需要显示所有大于>5的数;
// 创建仓库 store 状态,即数据:
// 类似于vue组件中的data、data 是组件自己的数据;
// state 中的数据整个vue项目的组件都能访问到;
const store = new Vuex.Store({
//开启严格模式
strict: true,
state: {
count: 10,
title: "大标题1",
list: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
},
//getters 类似于计算属性,用来从 store.state 状态数据中派生出一些状态的计算属性;
getters:{
// state中定义了list的数组,需要显示所有大于>5的数;
// 必须有返回值,返回值就是getters的值
// 形参第一个参数,就是state
filterList (state) { return state.list.filter(item => item > 5) }
}
})
Son3组件中获取:getters数据: 通过 this.$store.getters
访问定义的 getters
<template>
<div class="box">
<h2>Son3 子组件</h2>
从vuex中获取的值: <label>{{ $store.state.count }}</label>
<div>getters过滤数据 {{ $store.getters.filterList }}</div>
</div>
</template>
mapGetters
提供了一种高效、简洁的方式来访问 Vuex 中的 getters
,
减少了代码冗余,增强了组件的可读性和可维护性,是 Vue 应用中状态管理的重要工具之一
<template>
<div class="box">
<h2>Son3 子组件</h2>
从vuex中获取的值: <label>{{ $store.state.count }}</label>
<div>getters过滤数据 {{ $store.getters.filterList }}</div>
<div>mapGetters便携获取数据 {{ filterList }}</div>
</div>
</template>
<script>
//通过ES6 语法对象解构直接获取mapMutations...
import { mapMutations,mapActions,mapGetters } from 'vuex';
export default {
computed:{ ...mapGetters(['filterList']), }, //组件计算函数
}
</script>