Vue2(十二):Vuex环境搭建、Vuex工作原理、Vuex开发者工具、几个配置项、多组件共享数据、Vuex模块化

一、Vuex

1.概念

专门在Vue中实现集中式状态(数据)管理的一个Vue插件(use引入),对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。”

多组件比如a、b、c、d进行事件共享的时候,都想要a里的数据,而且他们互为兄弟,按以前的方法就得用全局事件总线,但是那样的话组件就太多了。Vuex就专门解决共享数据的问题。单独放在一块区域,大家都想得到的数据就放它里面,大家都可以读、写,a改完之后的x=4,那么b在拿到x也是4。

2.什么时候使用Vuex

(1)多个组件依赖于同一状态
(2)来自不同组件的行为需要变更同一状态

3.求和案例:纯Vue版

<template><div><h2>当前求和为:{{sum}}</h2><select v-model.number="n"><option value="1">1</option><option value="2">2</option><option value="3">3</option><!-- 这里除了最开始设置的数字1,其他都是字符串所以都加不了了 --><!-- 所以加 :value,当成js表达式去解析 或者加.number强制转换--></select><button @click="increment">+</button><button @click="decrement">-</button><button @click="incrementOdd">当前求和为奇数再加</button><button @click="incrementWait">等一等再加</button></div>
</template><script>
export default {name: "myCount",data(){return {sum:0,n:1,//用户选择的数字}},methods:{increment(){this.sum+=this.n},decrement(){this.sum-=this.n},incrementOdd(){if(this.sum%2==1){this.sum+=this.n}},incrementWait(){setTimeout(()=>{this.sum+=this.n},500)}}
};
</script>

4.Vuex的工作原理图

(1)构成

构成Vuex的三个对象由store管理,而且这三个对象数据类型都是obj,dispatch、commit函数就是store里的,所以我们得让任何vc都能看见store。

(2)流程

Vue Components是组件们,比如说我要加2,然后这个数据传给dispatch函数,传参过去:第一个参数:你要做的动作,第二个参数:数字。

然后你写的函数在Actions(数据类型是Object)就会有一个函数跟它对应,然后你自己再去调用commit函数(提交),到了mutations(数据类型也是Object),commit里的jia,mutations也会有一个jia跟它对应,同时它还会拿到两个参数:state状态和2。

mutate不用你调用,只需要在mutations里的jia写一句state.sum+=2,底层自动加2,sum就不是0是2了,然后Vuex帮你开始渲染render,页面上的sum就变化了。

这样看起来好像Actions有点没用,但是上面是后端接口,因为有的时候给dispatch传只传了动作没有值,就得去后端问一下数据(值得要发送ajax请求才能得到的时候,就需要用到Actions了)。

如果传过来就有值的话,可以直接调用commit。

二、Vuex环境搭建

1.安装Vuex

npm i vuex@3,Vue2对应vuex3版本,Vue3对应vuex4版本

2.引入并Use一下vuex

import Vuex from 'Vuex'
Vue.use(Vuex)

use了vuex然后就可以在vm中创建store对象了

3.创建store

新建一个store文件夹,在里面新建一个index.js

注意:所有的import都是先被提到代码最上方先执行然后再执行其他代码

在main.js引入插件并use vuex插件必须在import store之前,所以在main里面不管把use怎么移动都是先import store会报错,干脆把use代码写在index.js里,index里没有vue就引入vue

main.js:

//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//关闭Vue的生产提示
Vue.config.productionTip = false
import store from './store/index.js'
//创建vm
new Vue({el:'#app',render: h => h(App),beforeCreate() {Vue.prototype.$bus=this},store
})

index.js:

//该文件用于创建Vuex中最核心的store
//actions——响应组件中的动作
//引入Vue
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const actions={}
//mutations——用于操作数据
const mutations={}
//state——用于存储数据
const state={}
//创建store还得向外暴露
const store= new Vuex.Store({
actions,
mutations,
state
})export default  store

4.求和案例:Vuex版本

(1)首先把sum放进vuex

//state——用于存储数据
const state = {sum: 0,
}

(2)插值语法

<h2>当前求和为:{{$store.state.sum}}</h2>

(3)在组件中的回调用dispatch发给actions

methods:{increment(){this.$store.dispatch('jia',this.n)// $store是在vc身上的},

(4)actions来接数据,再调用commit函数

const actions = {jia(context,value) {context.commit('JIA',value)//context就是一个mini版的store// 调用commit函数,传过去方法和值}
}

(5)mutations来接数据

我们不是说actions里的东西要想用就得保证mutations里面也得有吗,所以写完actions里的东西之后在mutations里也加上,为了区分mutations里面都用大写

//mutations——用于操作数据
const mutations = {JIA(state,value) {state.sum+=value}
}

我们写的state里面只有一个sum=0,但是如果输出一下就能发现实际上还有getter和setter之类的,是vue给我们封装的,类似data

基础版index:
const actions = {// jia(context,value) {//     context.commit('JIA',value)//     //context就是一个mini版的store//     // 调用commit函数,传过去方法和值// },// jian(context,value) {//     context.commit('JIAN',value)// },//这两个都没必要绕弯再去找mutations,直接去找jiaOdd(context,value) {if(context.state.sum%2){context.commit('JIA',value)//这儿不用写JIAODD因为调用的都是jia,然后下面也就不用加JIAODD了}},jiaWait(context,value) {setTimeout(()=>{context.commit('JIA',value)},500)},
}
//mutations——用于操作数据
const mutations = {JIA(state,value) {state.sum+=value},JIAN(state,value) {state.sum-=value}
}
基础版myCount:
methods: {increment() {//this.$store.dispatch("jia", this.n);this.$store.commit("JIA", this.n);// $store是在vc身上的},decrement() {//this.$store.dispatch("jian", this.n);this.$store.commit("JIAN", this.n);//直接去找mutations},incrementOdd() {this.$store.dispatch("jiaOdd", this.n);},incrementWait() {this.$store.dispatch("jiaWait", this.n);},},
};

注意点:1.JIAODD、JIAWAIT里的方法都是JIA不用再单独写一个

2.JIA、JIAN都可以省略找Actions,直接去找Mutations

3.如果在actions直接写context.state.num+=value也能奏效,不用再找Mutations,但是!!这样开发者工具就失效了,所以还是得按照标准写。

4.业务逻辑写在组件里不写在action行不行?拿发票报销举例子,在组件里写就是调用第一个地儿然后传单号,然后调用第、、、个地儿再传单号很麻烦,直接告诉actions我要报销然后传单号,剩下的事让actions去解决。

三、Vuex开发者工具

跟vue位置一样,像表一样的图案就是Vuex的开发者工具,每一栏操作的后面有三个按钮,第一个按钮下载一样的是点击哪个,这个和它所有之前的都合并作为基底

第二个按钮是取消某一层,而且取消之后它后面的那些层也就都没了,就像盖楼一样,三层塌了上面的都得没

第三个按钮是时光穿梭到某个时候,展示那个时候的数据

哪条最绿说明页面正在呈现哪层

展示栏的右上角是导出和导入操作步骤

四、配置项

1.getters配置项

1、概念:当state中的数据需要经过加工后再使用时,可以使用getters加工,类似Vue中的计算属性computed与data。
2、类似于计算属性,但是好多组件都可以用,computer属性只能当前属性用(逻辑复杂或者逻辑还想复用的时候就用getters,得写返回值

//用于将state的数据进行加工
const getters={bigSum(state){return state.sum*10}
}

配置完记得暴露,调用一下:

<h2>当前和乘十为:{{ $store.getters.bigSum }}</h2>

2.mapstate与mapGetters

(1)mapstate

当我用插值语法用index中state中的数据的时候,都还得写$store.state、、、,写多了很麻烦,vuex为我们准备了一个方法:

首先先引入:

import {mapState} from 'vuex'
computed: {...mapState({ sum: "sum", school: "school", subject: "subject" }),},

...是es6语法,因为mapState也是一个对象,不能{  }里面再直接套一个对象{},又不是插值语法,...最后再加逗号,里面第一个是上面div要用的,第二个是index里的命名,自动就给你补齐$store.state了,然后在div里直接用:

 <h2>我在{{ school }}里学习{{ subject }}</h2>

a:a才能简写为a,但是num:‘num’不能简写(对象写法不能简写)

但是数组方法可以简写:注意:这是前后两个名字相同的情况下!!

一个名字两个用途,既可以用在index,也可以用在myCount组件

...mapState(['sum','school', 'subject' ]),

(2)mapGetters

用法一样

...mapGetters(['bigSum ' ]),
//...mapGetters({bigSum='bigSum'}),

3.mapActions与mapMutations

(1)mapMutations

借助mapMutations生成对应的方法,方法中会调用commit去联系Mutations

methods: {// increment() {//   //this.$store.dispatch("jia", this.n);//   this.$store.commit("JIA", this.n);//   // $store是在vc身上的// },// decrement() {//   //this.$store.dispatch("jian", this.n);//   this.$store.commit("JIAN", this.n);//   //直接去找mutations// },...mapMutations({increment:'JIA',decrement:'JIAN'}),

但是这么写还有点问题,确实被调用了,但是没有告诉人家n是多少,人家就默认传过去的value是鼠标点击事件,所以调用函数的时候得把n传过去

    <button @click="increment(n)">+</button><button @click="decrement(n)">-</button>

(2)mapActions

借助mapActions生成对应的方法,方法中会调用dispatch去联系Actions

 // incrementOdd() {//   this.$store.dispatch("jiaOdd", this.n);// },// incrementWait() {//   this.$store.dispatch("jiaWait", this.n);// },...mapActions({ incrementOdd: "jiaOdd", incrementWait: "jiaWait" }),

五、多组件共享数据

mapstate引入state里其他组件的数据,然后直接插值语法用就行

computed: {...mapState(['personList','sum'])},
<h2>上方组件的求和为:{{sum}}</h2>

六、Vuex模块化+命名空间

目的

让代码更好维护,让多种数据分类更加明确。

(1)Count组件

我们的action、mutations、state包含了两个组件的内容,如果内容很多的话,写一块就很乱,可以把他们分开写

//求和相关的配置
const countOptions={actions:{jiaOdd(context,value) {if(context.state.sum%2){context.commit('JIA',value)//这儿不用写JIAODD因为调用的都是jia,然后下面也就不用加JIAODD了}},jiaWait(context,value) {setTimeout(()=>{context.commit('JIA',value)},500)},},mutations:{JIA(state,value) {state.sum+=value},JIAN(state,value) {state.sum-=value},},state:{sum: 0,school:'bj',subject:'qd',},getters:{bigSum(state){return state.sum*10}},
}
//人员相关的配置
const personOptions={actions:{},mutations:{ADD_PERSON(state,value){//value就是人的对象obj state.personList.unshift(value)//往前放}},state:{personList:[{id:'001',name:'tt'}]},getters:{},
}
const store = new Vuex.Store({modules:{a:countOptions,b:personOptions//此时store里面就剩a、b了,mapState下的sum根本找不着了}
})

再想在组件里用可不能直接写num、school啥的了,因为store里只有a和b,就得带着a、b引用

computed: {//...mapState({ sum: "sum", school: "school", subject: "subject" }),...mapState(['a', 'b']),
<h2>当前求和为:{{ a.sum }}</h2><h2>当前和乘十为:{{ bigSum }}</h2><h2>我在{{ a.school }}里学习{{ a.subject }}</h2><h3>下方组件的总人数是:{{b.personList.length}}</h3>

哪儿都带着a、b调用吧又很麻烦,可以直接在computed里面给这些东西加a. b.

computed: {...mapState('a',['sum','school','subject']), ...mapState('b',['personList']), 

但是这个用法得配合开启命名空间namespaced:true,用,否则不生效,自己定义的配置后面都得写

const personOptions={namespaced:true,

包括方法啥的也得改是谁谁下的,后面是数组是对象都行

methods: {...mapMutations('a',{ increment: "JIA", decrement: "JIAN" }),...mapActions('a',{ incrementOdd: "jiaOdd", incrementWait: "jiaWait" }),},

(2)person组件

前面提到的要改正的不再多说,person要想调用ADD_PERSON方法,在前面加???/

this.$store.commit('b/ADD_PERSON',personObj)

又添加了一些功能并且把两个js分出去单独写了

index.js
//该文件用于创建Vuex中最核心的store
//actions——响应组件中的动作
//引入Vue
import Vue from 'vue'
import Vuex from 'vuex'
import personOptions from './myPerson'
import countOptions from './myCount'
Vue.use(Vuex)//创建store还得向外暴露
const store = new Vuex.Store({modules:{a:countOptions,b:personOptions//此时store里面就剩a、b了,mapState下的sum根本找不着了}
})export default store
myPerson.vue
<template><div><h1>人员列表</h1><h3>我想返回的列表的第一个人的名字是:{{ firstPersonName }}</h3><h2>上方组件的求和为:{{ a.sum }}</h2><input type="text" placeholder="请输入姓名" v-model="name" /><button @click="add">添加</button><button @click="addWang">添加一个姓王的人</button><button @click="addPersonServer">添加一个人</button><ul><li v-for="p in b.personList" :key="p.id">{{ p.name }}</li></ul></div>
</template><script>
import { mapState } from "vuex";
import { nanoid } from "nanoid";
export default {name: "myPerson",data() {return {name: "",};},computed: {...mapState(["a", "b"]),firstPersonName() {return this.$store.getters["b/firstPersonName"];//有.就不能有/,可以用[]代替.},},methods: {add() {const personObj = { id: nanoid(), name: this.name };this.$store.commit("b/ADD_PERSON", personObj);this.name = "";//输完之后框清除},addWang() {const personObj = { id: nanoid(), name: this.name };this.$store.dispatch('b/addPersonWang', personObj);this.name = "";},addPersonServer(){this.$store.dispatch('b/addPersonServer')}},
};
</script><style>
</style>
myCount.vue
<template><div><h2>当前求和为:{{ sum }}</h2><h2>当前和乘十为:{{ bigSum }}</h2><h2>我在{{ school }}里学习{{ subject }}</h2><h3>下方组件的总人数是:{{personList.length}}</h3><select v-model.number="n"><option value="1">1</option><option value="2">2</option><option value="3">3</option><!-- 这里除了最开始设置的数字1,其他都是字符串所以都加不了了 --><!-- 所以加 :value,当成js表达式去解析 或者加.number强制转换--></select><button @click="increment(n)">+</button><button @click="decrement(n)">-</button><button @click="incrementOdd(n)">当前求和为奇数再加</button><button @click="incrementWait(n)">等一等再加</button></div>
</template><script>
import { mapState, mapGetters, mapMutations, mapActions } from "vuex";
export default {name: "myCount",data() {return {n: 1, //用户选择的数字};},computed: {...mapState('a',['sum','school','subject']), ...mapState('b',['personList']), //sum: "sum", school: "school", subject: "subject" }),//...mapState('a',['a', 'b']),...mapGetters('a',['bigSum']),},methods: {...mapMutations('a',{ increment: "JIA", decrement: "JIAN" }),...mapActions('a',{ incrementOdd: "jiaOdd", incrementWait: "jiaWait" }),},
};
</script><style>
button {margin-left: 5px;
}
</style>
myCount.js
//求和相关的配置
const countOptions={namespaced:true,actions:{jiaOdd(context,value) {if(context.state.sum%2){context.commit('JIA',value)//这儿不用写JIAODD因为调用的都是jia,然后下面也就不用加JIAODD了}},jiaWait(context,value) {setTimeout(()=>{context.commit('JIA',value)},500)},},mutations:{JIA(state,value) {state.sum+=value},JIAN(state,value) {state.sum-=value},},state:{sum: 0,school:'bj',subject:'qd',},getters:{bigSum(state){return state.sum*10}},
}
export default countOptions
myPerson.js
import axios from "axios"
//import { response } from "express"
import { nanoid } from "nanoid"//人员相关的配置
const personOptions={namespaced:true,actions:{addPersonWang(context,value){if(value.name.indexOf('王')==0){context.commit('ADD_PERSONSE',value)//如果包括王而且位置还是第一个}else{alert ('添加的人得姓王!')}},addPersonServer(context){axios.get('http://api.uixsj.cn/hitokoto/get?type=social').then(response=>{context.commit('ADD_PERSONSE',{id:nanoid(),anme:response.data})},error=>{alert(error.message)}) }},mutations:{ADD_PERSONSE(state,value){//value就是人的对象obj state.personList.unshift(value)//往前放}},state:{personList:[{id:'001',name:'tt'}]},getters:{firstPersonName(state){return state.personList[0].name//这里的state是局部的}},
}
export default personOptions

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/587895.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python框架下的qt设计之JSON格式化转换小程序

JSON转换小程序 代码展示&#xff1a; 主程序代码&#xff1a; from PyQt6.QtWidgets import (QApplication, QDialog, QMessageBox )import sys import jsonclass MyJsonFormatter(jsonui.Ui_jsonFormatter,QDialog): # jsonui是我qt界面py文件名def __init__(self):super()…

Python+requests+Pytest+logging+allure+pymysql框架详解

一、框架目录结构 1)tools目录用来放公共方法存储,如发送接口以及读取测试数据的方法,响应断言 数据库断言 前置sql等方法;2)datas目录用例存储接口用例的测试数据,我是用excel来存储的数据,文件数据 图片数据等;3)testcases目录用来存放测试用例,一个python文件对应…

基于深度学习的危险物品检测系统(网页版+YOLOv8/v7/v6/v5代码+训练数据集)

摘要&#xff1a;本文详细介绍基于YOLOv8/v7/v6/v5的危险物品检测技术。主要采用YOLOv8技术并整合了YOLOv7、YOLOv6、YOLOv5的算法&#xff0c;进行了细致的性能指标对比分析。博客详细介绍了国内外在危险物品检测方面的研究现状、数据集处理方法、算法原理、模型构建与训练代码…

使用 Docker Compose 部署邮件服务器

使用 Docker Compose 部署邮件服务器 很多时候为了方便&#xff0c; 我们都直接使用第三方邮箱进行收发邮件。 但第三方邮箱有些要求定期修改密码&#xff0c;有些限制发邮箱的次数&#xff0c; 对于一些个人和企业来说&#xff0c; 有自己的域名和服务器为什么不自己搭建一个邮…

【六 (2)机器学习-机器学习建模步骤/kaggle房价回归实战】

一、确定问题和目标&#xff1a; 1、业务需求分析&#xff1a; 与业务团队或相关利益方进行深入沟通&#xff0c;了解他们的需求和期望。 分析业务流程&#xff0c;找出可能的瓶颈、机会或挑战。 思考机器学习如何帮助解决这些问题或实现业务目标。 2、问题定义&#xff1a;…

论文阅读RangeDet: In Defense of Range View for LiDAR-based 3D Object Detection

文章目录 RangeDet: In Defense of Range View for LiDAR-based 3D Object Detection问题笛卡尔坐标结构图Meta-Kernel Convolution RangeDet: In Defense of Range View for LiDAR-based 3D Object Detection 论文&#xff1a;https://arxiv.org/pdf/2103.10039.pdf 代码&…

元宇宙虚拟空间的场景构造(二)

前言 该文章主要讲元宇宙虚拟空间的场景构造&#xff0c;基本核心技术点&#xff0c;不多说&#xff0c;直接引入正题。 场景的构造 使用引入的天空模块 this.sky new Sky(this); 在Sky模块里&#xff0c;有设置对其中的阳光进行不同时间段的光线处理。而天空又是怎么样的…

c++20协程详解(一)

前言 本文是c协程第一篇&#xff0c;主要是让大家对协程的定义&#xff0c;以及协程的执行流有一个初步的认识&#xff0c;后面还会出两篇对协程的高阶封装。 在开始正式开始协程之前&#xff0c;请务必记住&#xff0c;c协程 不是挂起当前协程&#xff0c;转而执行其他协程&a…

【Vscode】无法将“python,pip,node,npm等”识别为cmdlet...问题

问题出现场景 新换个电脑&#xff0c;然后重新安装了软件&#xff0c;又复现一次又一次“老生常谈”的问题。 解决方法 网络答案吧五花八门&#xff0c;我采取一个我的场景解决可行的方案&#xff0c; 首先我的场景是&#xff0c;环境变量&#xff0c;配置路径都是没有问题…

STM32学习和实践笔记(4):分析和理解GPIO_InitTypeDef GPIO_InitStructure (c)

第二个成员变量是GPIOSpeed_TypeDef GPIO_Speed&#xff1b;也与int a一样同理。 GPIOSpeed_TypeDef是一个枚举类型&#xff0c;其定义如下&#xff1a; typedef enum { GPIO_Speed_10MHz 1, GPIO_Speed_2MHz, GPIO_Speed_50MHz }GPIOSpeed_TypeDef; #define IS_GPI…

【JavaEE初阶系列】——一万字带你了解 JUC常见类 以及 线程安全集合类(哈希表)

目录 &#x1f6a9;JUC(java.util.concurrent) 的常见类 &#x1f388;Callable 接口 &#x1f308;理解 Callable(相关面试题) &#x1f308;理解 FutureTask &#x1f4dd;线程创建方式 &#x1f388; ReentrantLock可重入锁 &#x1f308;ReentrantLock 优势&#x…

4.2学习总结

解题思路 遍历初始整数的全排列,然后计算每一个排列与原排列的的步数找到花费的最小值就行了 代码 #include <iostream> #include <cstdio> #include <fstream> #include <algorithm> #include <cmath> #include <deque> #include <…