Vuex
1、理解Vuex
1.1、Vuex是什么?
在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。
1.2.何时使用?
多个组件需要共享数据时
1.3.Vuex工作原理
1,具体流程:
插件里调用dispatch方法去找Actions,然后Actions里帮你调用commit找Mutations,然后由Mutations去调用Mutate去找State,然后State修改数据后重新渲染组件。
2,就像去餐厅吃饭的流程:客人->服务员->后厨->菜->你
2、搭建vuex环境
下载vuex插件:npm i vuex
①创建文件:src/store/index.js
一般会创建一个store文件夹,用来存放vuex的配置项
//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)
//准备actions对象——响应组件中用户的动作
const actions = {}
//准备mutations对象——修改state中的数据
const mutations = {}
//准备state对象——保存具体的数据
const state = {}
//创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state
})
②在main.js
中创建vm时传入store
配置项
在vue脚手架里,它会扫描代码里所有的import,先执行所有的引入操作,然后再执行其它的代码,包括使用等,所以,在两个import之间存在其它代码也不会打断它会先执行所有improt引入操作。
......
//引入store
import store from './store'
......
//创建vm
new Vue({
el:'#app',
render: h => h(App),
store
})
3、vuex基本使用
①初始化数据、配置actions
、配置mutations
,操作文件store.js
//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//引用Vuex
Vue.use(Vuex)
const actions = {
//响应组件中加的动作
jia(context,value){
// console.log('actions中的jia被调用了',miniStore,value)
context.commit('JIA',value)
},
}
const mutations = {
//执行加
JIA(state,value){
// console.log('mutations中的JIA被调用了',state,value)
state.sum += value
}
}
//初始化数据
const state = {
sum:0
}
//创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state,
})
②组件中读取vuex中的数据:$store.state.sum
③组件中修改vuex中的数据:$store.dispatch('action中的方法名',数据)
或 $store.commit('mutations中的方法名',数据)
备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch
,直接编写commit
4、求和案例
4.1、使用纯vue编写
src\App.vue
<template>
<div>
<Count/>
</div>
</template>
<script>
import Count from "./components/Count.vue"
export default {
name:"App",
components:{
Count
},
}
</script>
src\components\Count.vue
<template>
<div>
<h1>当前求和为:{{sum}}</h1>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="incremeent">+</button>
<button @click="decremeent">-</button>
<button @click="cremeentOdd">奇数再加</button>
<button @click="incremeentWait">等一等再加</button>
</div>
</template>
<script>
export default{
name:"Count",
data(){
return{
n:1,//用户选择的数字
sum:0,//当前的和
}
},
methods:{
incremeent(){
this.sum+=this.n;
},
decremeent(){
this.sum-=this.n;
},
cremeentOdd(){
if(this.sum%2){
this.sum+=this.n;
}
},
incremeentWait(){
setTimeout(()=>{
this.sum+=this.n;
},500);
}
}
}
</script>
<style scoped>
button{
margin-left:10px;
}
</style>
4.2、使用纯Vuex编写
搭配好Vuex环境,vuex插件3.0下载命令:npm i vuex@3
src\store\index.js
//该文件用于创建Vuex中最核心的Store
//引入Vuex
import Vue from "vue"
//引入vuex插件
import Vuex from "vuex";
//使用vuex插件
Vue.use(Vuex);
//准备actions,---用于响应组件中的动作
const actions={
//下面代码没有业务逻辑,直接在外面使用commit调用即可。
// jia:function(context,value){
// //console.log("jia被调用了");
// context.commit("JIA",value);
// },
// jian:function(context,value){
// context.commit("JIAN",value);
// },
jiaOdd(context,value){
console.log("处理了一些复杂逻辑...");
//交给jiaOddTest处理
context.dispatch("jiaOddTest",value);
},
jiaOddTest(context,value){
if(context.state.sum%2){
context.commit("JIA",value);
}
},
jiaWait(context,value){
//console.log("jiaWait被调用了");
setTimeout(() => {
context.commit("JIA",value);
}, 500);
}
}
//准备mutations,---用于操作数据(state)
const mutations={
JIA(state,value){
//console.log("mutations中的JIA被调用了");
state.sum+=value;
},
JIAN(state,value){
//console.log("mutations中的JIA被调用了");
state.sum-=value;
},
}
//准备state,---用于存储数据
const state={
sum:0,//当前的和
}
//创建store并导出
export default new Vuex.Store({
actions,
mutations,
state
})
src\App.vue
<template>
<div>
<Count/>
</div>
</template>
<script>
import Count from "./components/Count.vue"
export default {
name:"App",
components:{
Count
},
}
</script>
src\components\Count.vue
<template>
<div>
<h1>当前求和为:{{$store.state.sum}}</h1>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="incremeent">+</button>
<button @click="decremeent">-</button>
<button @click="cremeentOdd">奇数再加</button>
<button @click="incremeentWait">等一等再加</button>
</div>
</template>
<script>
export default{
name:"Count",
data(){
return{
n:1,//用户选择的数字
}
},
methods:{
incremeent(){
this.$store.commit("JIA",this.n);
},
decremeent(){
this.$store.commit("JIAN",this.n);
},
cremeentOdd(){
this.$store.dispatch("jiaOdd",this.n);
},
incremeentWait(){
this.$store.dispatch("jiaWait",this.n);
}
}
}
</script>
<style scoped>
button{
margin-left:10px;
}
</style>
5、getters配置项
-
概念:当state中的数据需要经过加工后再使用时,可以使用getters加工。相当于全局计算属性。
-
在
store.js
中追加getters
配置...... const getters = { bigSum(state){ return state.sum * 10 } } //创建并暴露store export default new Vuex.Store({ ...... getters })
-
组件中读取数据:
$store.getters.bigSum
6、四个map方法的使用
-
mapState方法:用于帮助我们映射
state
中的数据为计算属性computed: { //借助mapState生成计算属性:sum、school、subject(对象写法) ...mapState({sum:'sum',school:'school',subject:'subject'}), //借助mapState生成计算属性:sum、school、subject(数组写法) ...mapState(['sum','school','subject']), },
-
mapGetters方法:用于帮助我们映射
getters
中的数据为计算属性computed: { //借助mapGetters生成计算属性:bigSum(对象写法) ...mapGetters({bigSum:'bigSum'}), //借助mapGetters生成计算属性:bigSum(数组写法) ...mapGetters(['bigSum']) },
-
mapActions方法:用于帮助我们生成与
actions
对话的方法,即:包含$store.dispatch(xxx)
的函数methods:{ //靠mapActions生成:incrementOdd、incrementWait(对象形式) ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'}) //靠mapActions生成:incrementOdd、incrementWait(数组形式) ...mapActions(['jiaOdd','jiaWait']) }
-
mapMutations方法:用于帮助我们生成与
mutations
对话的方法,即:包含$store.commit(xxx)
的函数methods:{ //靠mapActions生成:increment、decrement(对象形式) ...mapMutations({increment:'JIA',decrement:'JIAN'}), //靠mapMutations生成:JIA、JIAN(对象形式) ...mapMutations(['JIA','JIAN']), }
备注:mapActions与mapMutations使用时,若需要传递参数需要:在模板中绑定事件时传递好参数,否则参数是事件对象。
7、多组件共享数据的案例
src\components\Count.vue
<template>
<div>
<h1>当前求和为:{{he}}</h1>
<h1>当前求和的10倍为:{{bigSum}}</h1>
<h3>我在{{xuexiao}},学习{{xueke}}</h3>
<h3 style="color:red">Person组件的总人数是:{{personList.length}}</h3>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="incremeent(n)">+</button>
<button @click="decremeent(n)">-</button>
<button @click="cremeentOdd(n)">奇数再加</button>
<button @click="incremeentWait(n)">等一等再加</button>
</div>
</template>
<script>
import {mapState,mapGetters,mapMutations,mapActions} from "vuex";
export default{
name:"Count",
data(){
return{
n:1,//用户选择的数字
}
},
computed:{
/* 手动写计算属性
he(){
return this.$store.state.sum;
},
xuexiao(){
return this.$store.state.school;
},
xueke(){
return this.$store.state.subject;
}, */
//借助mapState生成计算属性,从state中读取数据。(对象写法)
...mapState({he:"sum",xuexiao:"school",xueke:"subject",personList:"personList"}),
//----------
// bigSum(){
// return this.$store.getters.bigSum;
// },
//借助mapGetters生成计算属性,从getter中读取数据。(对象写法)
//...mapGetters({bigSum:"bigSum"}),
...mapGetters(["bigSum"]),
},
methods:{
/* 手动创建调用commit方法的函数
incremeent(){
this.$store.commit("JIA",this.n);
},
decremeent(){
this.$store.commit("JIAN",this.n);
},*/
//借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法)
...mapMutations({incremeent:"JIA",decremeent:"JIAN"}),
//mapMutations方法生成的函数是如下格式,
/*decremeent(value){
this.$store.commit("",value);
},*/
//----------------
/* 手动创建
cremeentOdd(){
this.$store.dispatch("jiaOdd",this.n);
},
incremeentWait(){
this.$store.dispatch("jiaWait",this.n);
},
*/
//借助mapActions生成对应的方法,方法中会调用dispatch去联系action(对象写法)
...mapActions({cremeentOdd:"jiaOdd",incremeentWait:"jiaWait"}),
}
}
</script>
<style scoped>
button{
margin-left:10px;
}
</style>
src\components\Person.vue
<template>
<div>
<h1>人员组件</h1>
<h3 style="color:red">Count组件的求和结果为:{{sum}}</h3>
<input type="text" placeholder="请输入名字" v-model="name">
<button @click="add">添加</button>
<ul>
<li v-for="p in personList " :key="p.id">{{p.name}}</li>
</ul>
</div>
</template>
<script>
import {nanoid} from "nanoid"
export default{
name:"Person",
data(){
return{
name:""
}
},
computed:{
personList(){
return this.$store.state.personList;
},
sum(){
return this.$store.state.sum;
}
},
methods:{
add(){
const personObj={id:nanoid(),name:this.name};
this.$store.commit("ADD_Person",personObj);
this.name="";
}
}
}
</script>
src\App.vue
<template>
<div>
<Count/>
<hr>
<Person/>
</div>
</template>
<script>
import Count from "./components/Count.vue"
import Person from "./components/Person.vue"
export default {
name:"App",
components:{
Count,
Person
},
}
</script>
src\store\index.js
//该文件用于创建Vuex中最核心的Store
//引入Vuex
import Vue from "vue"
//引入vuex插件
import Vuex from "vuex";
//使用vuex插件
Vue.use(Vuex);
//准备actions,---用于响应组件中的动作
const actions={
//下面代码没有业务逻辑,直接在外面使用commit调用即可。
// jia:function(context,value){
// //console.log("jia被调用了");
// context.commit("JIA",value);
// },
// jian:function(context,value){
// context.commit("JIAN",value);
// },
jiaOdd(context,value){
console.log("处理了一些复杂逻辑...");
//交给jiaOddTest处理
context.dispatch("jiaOddTest",value);
},
jiaOddTest(context,value){
if(context.state.sum%2){
context.commit("JIA",value);
}
},
jiaWait(context,value){
//console.log("jiaWait被调用了");
setTimeout(() => {
context.commit("JIA",value);
}, 500);
}
}
//准备mutations,---用于操作数据(state)
const mutations={
JIA(state,value){
//console.log("mutations中的JIA被调用了");
state.sum+=value;
},
JIAN(state,value){
//console.log("mutations中的JIA被调用了");
state.sum-=value;
},
ADD_Person(state,value){
console.log("ADD_Person被调用了");
state.personList.unshift(value);
}
}
//准备state,---用于存储数据
const state={
sum:0,//当前的和
school:"家里蹲",
subject:"前端",
personList:[{id:"001",name:"张三"}]
}
//准备getters,---用于将state中的数据进行加工。
const getters={
bigSum(state){
return state.sum*10;
}
}
//创建store并导出
export default new Vuex.Store({
actions,
mutations,
state,
getters
})
8、模块化+命名空间
目的:让代码更好维护,让多种数据分类更加明确。
①修改store.js
为了解决不同模块命名冲突的问题,将不同模块的namespaced: true
z之后在不同页面中引入gette r
actions
mutations
时,需要加上所属的模块名。
const countAbout = {
namespaced:true,//开启命名空间
state:{x:1},
mutations: { ... },
actions: { ... },
getters: {
bigSum(state){
return state.sum * 10
}
}
}
const personAbout = {
namespaced:true,//开启命名空间
state:{ ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
countAbout,
personAbout
}
})
②开启命名空间后,组件中读取state数据
//方式一:自己直接读取
this.$store.state.personAbout.list
//方式二:借助mapState读取:
...mapState('countAbout',['sum','school','subject']),
③开启命名空间后,组件中读取getters数据:
//方式一:自己直接读取
this.$store.getters['personAbout/firstPersonName']
//方式二:借助mapGetters读取:
...mapGetters('countAbout',['bigSum'])
④开启命名空间后,组件中调用dispatch
//方式一:自己直接dispatch
this.$store.dispatch('personAbout/addPersonWang',person)
//方式二:借助mapActions:
...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
⑤开启命名空间后,组件中调用commit
//方式一:自己直接commit
this.$store.commit('personAbout/ADD_PERSON',person)
//方式二:借助mapMutations:
...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),
模块化修改上面的多组件共享数据的案例
①在store里建立countOption.js和peresonOption.js
②分别将原来src\store\index.js里countOption和peresonOption两个模块的代码打包进相应的js文件并且暴露出来。然后再引用即可。
src\store\countOption.js
//求和相关的配置
export default{
namespaced:true,//添加命名空间,否则使用vuex提供的四个方法无法识别
//准备actions,---用于响应组件中的动作
actions:{
jiaOdd(context,value){
console.log("处理了一些复杂逻辑...");
//交给jiaOddTest处理
context.dispatch("jiaOddTest",value);
},
jiaOddTest(context,value){
if(context.state.sum%2){
context.commit("JIA",value);
}
},
jiaWait(context,value){
//console.log("jiaWait被调用了");
setTimeout(() => {
context.commit("JIA",value);
}, 500);
}
},
//准备mutations,---用于操作数据(state)
mutations:{
JIA(state,value){
//console.log("mutations中的JIA被调用了");
state.sum+=value;
},
JIAN(state,value){
//console.log("mutations中的JIA被调用了");
state.sum-=value;
},
},
//准备state,---用于存储数据
state:{
sum:0,//当前的和
school:"家里蹲",
subject:"前端",
},
//准备getters,---用于将state中的数据进行加工。
getters:{
bigSum(state){
return state.sum*10;
}
}
}
src\store\peresonOption.js
//人员管理相关的配置
import axios from "axios";
import {nanoid} from "nanoid";
export default{
namespaced:true,//添加命名空间,否则使用vuex提供的四个方法无法识别
//准备actions,---用于响应组件中的动作
actions:{
//只添加性别王的
addPersonWang(context,value){
if(value.name.indexOf('王')===0){
context.commit("ADD_Person",value);
}else{
alert("添加的人必须姓王");
}
},
personServeer(context){
axios.get("https://api.uixsj.cn/hitokoto/get?type=social").then(response=>{
context.commit("ADD_Person",{id:nanoid(),name:response.data});
},error=>{
alert(error.message);
});
}
},
//准备mutations,---用于操作数据(state)
mutations:{
ADD_Person(state,value){
console.log("ADD_Person被调用了");
state.personList.unshift(value);
}
},
//准备state,---用于存储数据
state:{
personList:[{id:"001",name:"张三"}]
},
getters:{
firstPersonName(state){
//这里的传进来的state就是peresonOption这个里面的局部的state,不是全局总的state
return state.personList[0].name;
}
}
}
src\store\index.js
//该文件用于创建Vuex中最核心的Store
//引入Vuex
import Vue from "vue"
//引入vuex插件
import Vuex from "vuex";
//使用vuex插件
Vue.use(Vuex);
//求和相关的配置
import countOption from "./countOption.js";
//人员管理相关的配置
import peresonOption from "./peresonOption.js"
//创建store并导出
export default new Vuex.Store({
modules:{
countAbout:countOption,
personAbout:peresonOption
}
})
src\components\Person.vue
<template>
<div>
<h1>人员组件</h1>
<h3 style="color:red">Count组件的求和结果为:{{sum}}</h3>
<h3>列表中第一个人的名字是:{{firstPersonName}}</h3>
<input type="text" placeholder="请输入名字" v-model="name">
<button @click="add">添加</button>
<button @click="addWang">添加一个姓王的人</button>
<button @click="addPersonSerever">添加一个随机的人</button>
<ul>
<li v-for="p in personList " :key="p.id">{{p.name}}</li>
</ul>
</div>
</template>
<script>
import {nanoid} from "nanoid"
export default{
name:"Person",
data(){
return{
name:""
}
},
computed:{
personList(){
return this.$store.state.personAbout.personList;
},
sum(){
return this.$store.state.countAbout.sum;
},
firstPersonName(){
return this.$store.getters["personAbout/firstPersonName"];
}
},
methods:{
add(){
const personObj={id:nanoid(),name:this.name};
this.$store.commit("personAbout/ADD_Person",personObj);
this.name="";
},
addWang(){
const personObj={id:nanoid(),name:this.name};
this.$store.dispatch("personAbout/addPersonWang",personObj)
},
addPersonSerever(){
this.$store.dispatch("personAbout/personServeer");
}
}
}
</script>
src\components\Count.vue
<template>
<div>
<h1>当前求和为:{{sum}}</h1>
<h1>当前求和的10倍为:{{bigSum}}</h1>
<h3>我在{{school}},学习{{subject}}</h3>
<h3 style="color:red">Person组件的总人数是:{{personList.length}}</h3>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="incremeent(n)">+</button>
<button @click="decremeent(n)">-</button>
<button @click="cremeentOdd(n)">奇数再加</button>
<button @click="incremeentWait(n)">等一等再加</button>
</div>
</template>
<script>
import {mapState,mapGetters,mapMutations,mapActions} from "vuex";
export default{
name:"Count",
data(){
return{
n:1,//用户选择的数字
}
},
computed:{
//借助mapState生成计算属性,从state中读取数据。
//...mapState("countAbout",{jia:"sum",xuexiao:"school",kemu:"subject"}), //这样写可以用你定义的键使用值
...mapState("countAbout",["sum","school","subject"]), //这样只能通过值名当作键使用
...mapState("personAbout",["personList"]),
//----------
//借助mapGetters生成计算属性,从getter中读取数据。(对象写法)
...mapGetters("countAbout",["bigSum"]),
},
methods:{
//借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法)
...mapMutations("countAbout",{incremeent:"JIA",decremeent:"JIAN"}),
//借助mapActions生成对应的方法,方法中会调用dispatch去联系action(对象写法)
...mapActions("countAbout",{cremeentOdd:"jiaOdd",incremeentWait:"jiaWait"}),
}
}
</script>
<style scoped>
button{
margin-left:10px;
}
</style>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?