专门在Vue中实现集中式状态数据管理的一个Vue插件,对Vue的应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。
https://github.com/vuejs/vuexhttps://github.com/vuejs/vuex
当通过全局事件总线或者消息订阅与发布传递信息时候,给多个组件要一一发送,如果修改又得一一进行修改
vuex可以解决一一发送这一弊端
所以vuex主要使用场景就是:
- 当多个组件依赖同一个状态
- 多个不同组件的行为需要变成更同一状态
当前求和为:{{sum}}
- 首先绑定数据
- 布置页面并设置按钮执行事件
- 设置执行事件的逻辑
- 存在问题:绑定数据的时候不是数值
- 利用:进行绑定value值
- 或者直接使用修饰符:number
vuex重要组成部分:Actions、Mutations、State
State:对象,能保存很多key-value默认值
组件:组件中存在各种方法,调用api-dispatch(‘动作类型’,动作值)
Actions:object对象,key和上面动作类型对上,然后调用key所对应的函数,然后自己调用commit(提交)
Mutations:object对象,这个对象上面也存在key和上面动作类型对上,然后调用key所对应的函数,函数包含(整个state,动作值)自动进行mutate
然后state就会发生变化,然后重新进行解析
Action,ajax获取到Backend API获取其他服务器上的数据
当Action的值自己知道,那么就直接可以组件执行commit给Mutations
Devtools:直接和mutations对话
简单理解:
组件 === 客人
Action === 服务员
Mutations === 后厨
State === 菜
安装vuex:注意vue3成为默认版本,vuex更新到了4版本(在vuex2项目中安装vuex3)
npm i vuex@3
插件的使用:目的是使用vuex之后在vm中存在store配置
main中引入vuex
使用vuex,引入和使用在main文件省略(因为会报错)
然后vue实例中配置store
注意:如果没有引入并使用vuex那么就不会在vm或者vc中产生store配置
就算再vm实例中配置很多自定义匹配项但是vm不认就会丢弃
new Vue({ el:'#app', render: h => h(App), //store:'hello',//没有引入vux之前再组件中无法找到store store,//简写方式:需要在main中引入并使用之后才能配置,然后就会出现在vc和vm中 }, })
配置store文件:看见store就等于看见vuex的服务员、后厨、菜
- src中配置store文件
- 然后在其中创建index.js文件
设置store :
配置以上三个重要组成部分
然后引入vuex并进行实例化(注意是实例化store)并进行暴露
然后将配置放在实例中(简写方式:key值相等可以简写)
//引入vuex import Vuex from 'vuex' //配置actions--用于响应组件中的动作 const actions = {} //准备mutations--用于操作数据 const mutations = {} //准备state--用于存储数据 const state = {} //创建并暴露store export default new Vuex.Store({ actions, mutations, state, })
然后在main文件中引入store
// 引入store // import store from './store/index'后面的文件可以省略(必须是index) import store from './store'
报错:Vue.use(vuex)应该在store实例化之前
所以在main中不进行引入vuex和使用(上面提到的报错)
因为引入store时候会自动在使用vuex之前解析出来
直接在store文件中引入vue、vuex,并进行使用vue.use(vuex)
import Vue from 'vue' //引入vuex import Vuex from 'vuex' // 使用插件在创建store之间进行使用vuex Vue.use(Vuex)
- 首先将数据放在state中,然后组件中关于sum的计算就不能执行
- 组件中设置方法传给actions
increment(){ // 此处可以不通过actions直接执行mutations获取数据执行方法 this.$store.dispatch('jia',this.n) },
- actions中配置方法:方法中存在两个参数,分别是上下文和传入的值
- 并进行上传上下文中的计算方式
//两个参数:一个是miniStore(context),后面是value jia(context, value) { console.log(context, value); context.commit('JIA',value) },
- 在mutation中进行配置上下下文需要的计算方式
- mutation中的计算方式应该是大写方式(方便观看)
- mutation中方法的参数一个是state,一个是传入的value值
JIA(state,value) { // console.log(state,value);参数分别是数据监测state中的数据和传入的参数 state.sum += value },
- 页面读取效果应该从组件中进行获取,直接获取,不需要进行this获取
- 显示初始值根据vuex中配置进行设置
当前求和为:{{$store.state.sum}}
- 组件中直接传入vuex计算方式
incrementOdd(){ this.$store.dispatch('jiaOdd',this.n) }, incrementWait(){ this.$store.dispatch('jiaWait',this.n) },
- store文件的actions中配置计算方式:奇数计算和等一等计算
jiaOdd(context, value) { if (context.state.sum % 2) { // 上下文直接提交执行动作 context.commit('JIA', value) } }, jiaWait(context, value) { setTimeout(() => { context.commit('JIAN',value) },500) },
- mutations中的方法还是 上面配置的方法
const mutations = { JIA(state,value) { state.sum += value }, JIAN(state,value) { state.sum -= value } }
可以直接通过mutations中获取到的计算方法:在组件中直接使用commit进行获取
increment(){ this.$store.commit('JIA',this.n) }, decrement(){ this.$store.commit('JIAN',this.n) },
上面的JIA和JIAN都在mutations中存在
开发者工具简单理解
- 直接与mutations进行对话,最后的计算都是通过mutations中的计算
开发者工具中每一步存在的操作
- 秒表按钮:直接恢复到指定的计算效果
- 清除效果:直接删除当前的计算效果(删除中间的,所有以来其产生的都会清除)
- 下载按钮:合并当前点击之前的所有计算步骤,并合并
右上角的三个按钮
- 红点:不会在捕获计算步骤
- 清除按钮:清除空所有的操作记录
- 下载:合并所有步骤
右下角的两个按钮
- 导出:将计算过程的最终效果复制(存在在剪切板)
- 导入:直接粘贴在导入框中(Esc退出)
为什么需要actions中的context参数
当业务逻辑比较复杂时候,需要先在最外层执行某些事情,然后dispatch某个方法
然后在第二层再处理一点事情,然后调用dispatch
最后一层执行一点事情然后再执行commit
为什么要将简单的计算方式commit给mutations
如果执行奇数计算不用利用commit提交给mutation,可以直接使用state进行计算
context.state.sum += value可以执行但是不规范(开发者工具无法捕获)
为什么将逻辑写在actions而不写在组件方法中
如果执行的动作需要多个服务器进行判断,那么在自身组件写不能实现复用
不是必须存在,如果要将state默认数据进行一些复杂操作就会体现其作用
- 参数就是state中的数据,利用返回值进行计算
// 准备getters用于将state中的数据进行直接加工 const getters = { // state参数就是state bigSum(state) { return state.sum * 10 } }
- 配置并暴露
export default new Vuex.Store({ actions, mutations, state, getters, })
- 模板获取
当前求和放大10倍数为:{{$store.getters.bigSum}}
以下内容都是在组建中完成
优化获取数据和优化对数据的复杂操作:粗糙方法
直接使用计算属性获取到sum:来自于当前组件的store的state
模板简单了,但是代码还是冗余
采用一种方式可以获取数据并进行自己命名
mapState:映射数据
- 首先进行引入
import {mapState} from 'vuex'
- 计算属性中进行获取(对象和数组方法进行获取)
- 利用剩余参数进行获取,通过开发者工具最后显示的是vuex的绑定
//借助mapstate从state中获取数据 (对象写法):计算属性名字和获取数据名字不同 ...mapState({he:'sum',xuexiao:'school',xueke:'subject'}) //通过数组方式进行获取值(计算属性名字和获取数据名字相同) ...mapState(['sum','school','subject']),
mapGetters
- 首先引入mapGetters
import {mapGetters} from 'vuex'
- 在计算属性中进行获取
computed:{ ...mapGetters({beishu:'bigSum'}),//对象写法 ...mapGetters(['bigSum']),//数组写法 }
mapMutations
- 首先引入mapMutations
import {mapMutations} from 'vuex'
- 方法中进行获取:注意会出现问题:获取到的是鼠标事件为没有value
- 直接在模板中传递数据
...mapMutations({increment:'JIA',decrement:'JIAN'}),//对象写法 ...mapMutations(['JIA','JIAN']),//数组写法(使用数组引入之后的名就是引入的名字)
mapActions
- 首先引入mapActions
import {mapActions} from 'vuex'
- 方法中进行获取:首先利用模板进行传递数据
...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'}),//对象形式 ...mapActions(['jiaOdd','jiaWait']),//数组形式,注意没有生成名字
以上两个传value值不仅可以通过模板进行获取,还可以通过方法直接进行获取(不使用)
increment(){ this.接收自定义名字(value值) }
创建新的person组件:配置一个不同页面效果
进行配置组件和vuex
- state数据配置一个对象,在组件中进行遍历获取,计算属性可以直接简化遍历获取源
//store数据编写 personList: [ {id: '001', name:'张三'} ] //组件中遍历名字
//获取数据 personList(){ // 注意获取数据需要使用return进行返回 return this.$store.state.personList }, // 获取数据 // ...mapState(['personList'])
- {{p.name}}
- 配置按钮点击方法:依赖nanoid生成的新的对象并commit
- 直接在mutations中添加一个方法(给数据添加人)
add(){ const personObj = {id:nanoid(),name:this.name} this.$store.commit('ADD_PERSON',personObj) this.name = '' } //vuex ADD_PERSON(state, value) { state.personList.unshift(value) }
vuex中的不同组件使用的vuex数据和方法都不同:多个不同的vuex内容混合在一块容易混乱
1. 区分组件对象(命名)并配置namespaced配置(开启命名空间)
- 进行区分:此处只演示person-vuex模块
- 确定分类:配置项namespaced:true默认值false
- 通过以上配置组件中获取模块化名字才会被认识
const personOptions = { namespaced: true,//此处默认值false actions: { // 如果包含王:判断0==0 为正确则提交使用mution方法 addPersonWang(context, value) { if (value.name.indexOf('王') === 0) { context.commit('ADD_PERSON',value) } else { alert('添加姓王的人') } } }, mutations: { ADD_PERSON(state, value) { state.personList.unshift(value) } }, state: { personList: [ {id: '001', name:'张三'} ] }, }
2. 暴露组件模块并配置自定义名字
- 进行区分之后的store中暴露就不是直接暴露vuex配置:利用modules配置进行区分
- 注意通过模块化之后进行获取就会出现问题:获取不到数据和actions等
- 但是组件模块化之后就存在了自定义名字
//创建并暴露store export default new Vuex.Store({ // 暴露store的配置:上面配置命名之后以下才会认识 modules: { countAbout: countOptions, personAbout:personOptions } })
3. 组件中获取模块化内的数据就需要通过先区分模块再进行引入
- 然后组件中模板直接获取数据:简易方法需要配合上方的自定义名字
...mapState('countAbout',['sum','school','subject','personList']), ...mapState('personAbout',['personList']),
computed:{ ...mapState('countAbout',['sum','school','subject','personList']), ...mapState('personAbout',['personList']), ...mapGetters('countAbout',['bigSum']),//数组写法 }, methods: { ...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),//对象写法 ...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'}),//对象形式 },
4. 通过原生方法获取vuex中数据和方法并进行添加时候的代码格式
注意这里使用 / 进行分割
//获取vuex中数据 computed:{ personList(){ // 注意获取数据需要使用return进行返回 return this.$store.state.personAbout.personList }, } //对模块化vuex中的数据进行获取并执行mutations的方法时候代码格式 add(){ const personObj = {id:nanoid(),name:this.name} this.$store.commit('personAbout/ADD_PERSON',personObj) this.name = '' },
5.通过原生方法获取模块化中的getters
获取数据的时候需要通过【】获取对象数据方法:包裹组件模块暴露的自定义名字
//上面组件中已经配置添加姓王名字 //组件模块中配置getters-获取第一个人名 getters: { firstPersonName(state) { return state.personList[0].name } },
//组件中使用 computed:{ firstPersonName(){ // 获取对象方法数组获取 return this.$store.getters['personAbout/firstPersonName'] } },
6. 优化模块化代码
创建单独的vuex文件:将vuex配置都放在其中并暴露
创建一个总的vuex:
- 总文件中引入单个的vuex
- 并暴露
//该文件创建vuex最重要的store import Vue from 'vue' //引入vuex import Vuex from 'vuex' // 引入store模块 import countOptions from './count' import personOptions from './person' // 使用插件在创建store之间进行使用vuex Vue.use(Vuex) //创建并暴露store export default new Vuex.Store({ // 暴露store的配置:上面配置命名之后以下才会认识 modules: { countAbout: countOptions, personAbout:personOptions } })
7.服务器获取人名-对应组件中进行编写
此处使用一个免费api:
https://api.uixsj.cn/hitokoto/get?type=socialhttps://api.uixsj.cn/hitokoto/get?type=social
//首先引入nanoid import { nanoid } from "nanoid" //actions addPersonServe(context) { // 发送get请求获取数据 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) } ) },
//组件中进行设置方法 //进行获取actions中的方法 addPerson(){ this.$store.dispatch('personAbout/addPersonServe') }