Vuex

news/2024/7/7 20:05:28/文章来源:https://www.cnblogs.com/wztblogs/p/18280087

Vuex

什么是Vuex?

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

之前想要传递数据,可以使用全局事件总线/消息订阅去实现,但是如果有很多组件都想要去读和写 某个组件中的数据,那么需要在每个组件中去绑定或触发 读/写的事件,一旦组件数过多代码就会变得很复杂,所以可以使用vuex去实现这个目的。

 

Vuex 工作原理

vuex

在Vuex中有三个对象 Actions、Mutations、State

State 里面保存的是 数据,以key-value 的形式保存

 

一个动作/函数 的执行流程:

  • 在Vue 组件中 点击了加1按钮,想让一个数字加1,但这个数字不在该组件自身,在Vuex的state里

  • 调用dispatch() 第一个参数是 要进行的动作类型,比如是”add“,第二个参数是 要加几

  • 调用了dispatch后,你执行的动作和值就来到了 Actions,Actions也是一个Object对象,里面一定会有一个“ add”,它的值是一个函数,当你传进来的 “add” 能和 Actions中的 "add" 对上,就会引起 这个函数的调用,这个函数一旦被调用就受到了传进来的 数值

  • 在 ”add“ 对应的函数中自己去调用 commit 函数 ,commit 函数 和 dispatch 函数的参数相同

  • 执行完 commit 函数后,就走到了 Mutations 对象中,它也有 ”add“ ,值也是 函数,在这个函数中 会拿到两个东西,第一个是 state 第二个是你传进来的数据,修改state 中的数据,底层会自动调用 Mutate,就会引起state 中数据的变化

  • 然后重新解析组件,渲染

在Action 中 发送 Ajax请求,当你不需要发送Ajax请求时,可以直接调用 commit 函数

上述三个对象 Actions、Mutations、State都是由Store管理的 ,调用也是通过store

 

搭建Vuex环境

1.安装Vuex

npm i vuex@3

这里我们需要安装vuex3版本,因为 vuex4只能在 vue3中使用

2.Vue.use(Vuex)

这里的注意点是 在 使用 Vue.use(Vuex) 必须在创建store 实例之前,所以需要先创建store实例

按照官网的写法,是在src目录下创建一个 store目录,在该目录下创建 index.js,在该文件中创建 store实例和使用 vuex插件

//该文件用于创建Vuex中最核心的Store
​
//引入Vue
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//使用vuex 插件
Vue.use(Vuex)
​
//准备Actions--用于响应组件中的动作
const actions = {}
//准备 mutations--用于操作数据
const mutations = {}
//准备state--用于存储数据
const state = {}
​
//创建并暴露 store
export default new Vuex.Store({   actions,   mutations,   state
})

3.在 main.js 引入 store,并传入 vm 中

import Vue from "vue";
import App from './App'
import store from './store/index'new Vue({   el:"#app",   render:h => h(App),   store,   beforeCreate(){       Vue.prototype.$bus = this   }
})

 

修改 计数案例

在没有使用vuex 的时候的计数案例:

<template> <div>   <h1>当前的值为:{{totalNum}}</h1>   <select v-model="selectNum">       <option :value="1">1</option>       <option :value="2">2</option>       <option :value="3">3</option>   </select>   <button @click="addNum">+</button>   <button @click="decrementNum">-</button>   <button @click="addNumOdd">奇数加</button>   <button @click="addWait">等会加</button> </div>
</template>
​
<script>
​
export default {   name:'Counts',   data(){       return{           totalNum:0,           selectNum:1       }    },   methods:{       addNum(){           this.totalNum += this.selectNum       },       decrementNum(){           this.totalNum -= this.selectNum       },       addNumOdd(){           if(this.totalNum % 2){               this.totalNum+=this.selectNum           }       },       addWait(){           setTimeout(() => {               this.totalNum+=this.selectNum           },500)       }   }
}
</script>
​
<style scoped>   button{       margin-left: 5px;   }
</style>

 

使用 Vuex来修改计数案例

按照Vuex的执行流程

  • 首先把 定义在 Counts组件中的数据 放到 store 的 state 对象中

    const state = {   totalNum:0
    }
  • 在 Counts 组件的方法中调用 dispatch

    methods:{       addNum(){           this.$store.dispatch("addNumber",this.selectNum)       },       decrementNum(){           this.$store.dispatch("decrement",this.selectNum)       },       addNumOdd(){           if(this.$store.state.totalNum % 2){               this.$store.dispatch("addNumber",this.selectNum)           }       },       addWait(){           setTimeout(() => {               this.$store.dispatch("addNumber",this.selectNum)           },500)       }
    }
  • 在 store的 actions 和 mutations 中 定义 dispatch 传入的方法

    const actions = {   addNumber(context,value){       context.commit("ADDNUMBER",value)   },   decrement(context,value){       context.commit("DECREMENT",value)   }
    }
    //准备 mutations--用于操作数据
    const mutations = {   ADDNUMBER(state,value){       state.totalNum += value   },   DECREMENT(state,value){       state.totalNum -= value   },
    }
  • 在之前的模板中 的差值语法不能直接使用 totalNum,而是 用 $store.state.totalNum

如果没有网络请求或其他业务逻辑,组件中 也可以越过actions,即不写dispatch,直接写commit

 

store 中的getters 配置项

1.当state中的数据需要经过加工后再使用,并且这个加工方式需要多次复用,可以在store 中配置 getters

2.getters 中计算出来的属性,用函数表示,参数是 state,还要把getters 传给Store

const getters = {bigSum(state){return state.sum * 10}
}
​
export default new Vuex.Store({   ...   getters
})

3.在组件中使用 $store.getters.bigSum 来获取这个值

 

四个map方法的使用

当我们在组件模板中去使用 state 中的数据时,每次都需要写 $store.state.xxx

我们就可以把 xxx 作为计算属性,“$store.state" 从计算属性中传过去,这样在模板中就简化了代码

但是 这样还会产生很多的计算属性,那么这时候就可以借助 vue提供的方法生成计算属性

  1. mapState:帮助我们映射state 中的数据为计算属性

    computed:{   //第一种写法:对象写法   ...mapState({sum:'sum',school:'school',subject:'subject'})   //第二种写法:数组写法   ...mapState(['sum','school','subject'])
    }

    需要注意 数组写法,必须保证计算属性的名字和 你想要在state中拿到数据的名字一致

    mapState 前的 "..." 的含义是 把 这个方法里面的对象追加到 computed中

  2. mapGetters:帮助我们映射getters 中的数据为计算属性

    使用方法和 mapState 相同,需要注意的是这两个方法需要从vuex 中用 import引入

  3. mapActions:用于帮助我们生成与actions对话的方法,即包含$store.dispatch(xxx) 的函数

    methods:{   //第一种写法,对象写法   ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})   //第二种写法:数组写法   ...mapAction(['jiaOdd','jiaWait'])
    }
  4. mapMutation:用于帮助我们生成与 mutations对话的方法,即包含 $.store.commit(xxx) 函数

    使用方法和 mapActions 相同

注意:mapActions和 mapMutation 使用时,若需要传递参数,在模板中绑定事件时传递好参数,否则参数就是事件对象

下面是案例:

<template> <div>   <!-- <h1>当前的值为:{{$store.state.totalNum}}</h1> -->   <!-- <h3>当前的值放大十倍为:{{$store.getters.bigNum}}</h3> -->   <h1>当前的值为:{{totalNum}}</h1>   <h3>当前的值放大十倍为:{{bigNum}}</h3>   <select v-model="selectNum">       <option :value="1">1</option>       <option :value="2">2</option>       <option :value="3">3</option>   </select>   <!-- <button @click="addNum">+</button>   <button @click="decrementNum">-</button> -->   <!-- 调用方法时需要传参,否则参数就是鼠标点击事件-->   <button @click="ADDNUMBER(selectNum)">+</button>   <button @click="DECREMENT(selectNum)">-</button>   <button @click="addNumOdd(selectNum)">奇数加</button>   <button @click="addWait(selectNum)">等会加</button> </div>
</template>
​
<script>
import {mapState,mapGetters,mapActions,mapMutations} from 'vuex'
export default {   name:'Counts',   data(){       return{           selectNum:1       }    },   computed:{       ...mapState(['totalNum']),       ...mapGetters(['bigNum'])   },   methods:{       //这里用的都是 数组的方式,要求传入的名字要和store中 Actions和Mutations中的名字一致,使用时也是用这个名字       ...mapActions(['addNumOdd','addWait']),       ...mapMutations(['ADDNUMBER','DECREMENT'])   }
}
</script>
​
<style scoped>   button{       margin-left: 5px;   }
</style>
//准备Actions--用于响应组件中的动作
const actions = {   addNumOdd(context,value){       if(context.state.totalNum % 2){           context.commit("ADDNUMBER",value)       }   },   addWait(context,value){       setTimeout(() => {           context.commit("ADDNUMBER",value)       },500)   }
}
//准备 mutations--用于操作数据
const mutations = {   ADDNUMBER(state,value){       state.totalNum += value   },   DECREMENT(state,value){       state.totalNum -= value   },
}
//准备state--用于存储数据
const state = {   totalNum:0
}
​
//准备getters--用于计算state中的数据
const getters = {   bigNum(){       return state.totalNum * 10   }
}

 

Vuex模块化

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

上面的案例只有一个组件,现在我们再创建一个组件,体现出多组件共享数据

<template> <div>   <h1>人员列表</h1>   <h3>列表中第一个人是:{{firstPerson.name}}</h3>   <h3 style="color-red">Counts组件计算后的值:{{counts}}</h3>   <input type="text" v-model="personName">    <button @click="addPerson">添加</button>   <button @click="addPersonWang">添加姓王的人</button>   <ul>       <li v-for="person in personList" :key="person.id">{{person.name}}</li>   </ul> </div>
</template>
​
<script>
import {nanoid} from 'nanoid'
export default {   name:'Persons',   data(){       return{           personName:''       }   },   computed:{       personList(){           return this.$store.state.personList       },       firstPerson(){           return this.$store.getters.firstPerson       },       counts(){           return this.$store.state.totalNum       }   },   methods:{       addPerson(){           const person = {id:nanoid(),name:this.personName}           this.$store.commit('ADD_PERSON',person)           this.personName = ''       },       addPersonWang(){           const person = {id:nanoid(),name:this.personName}           this.$store.dispatch('addPersonWang',person)           this.personName = ''       }   }
}
</script>
​
<style scoped>   button{       margin-left: 5px;   }
</style>
//该文件用于创建Vuex中最核心的Store
​
//引入Vue
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//使用vuex 插件
Vue.use(Vuex)
​
//准备Actions--用于响应组件中的动作
const actions = {   // addNumber(context,value){   //     context.commit("ADDNUMBER",value)   // },   // decrement(context,value){   //     context.commit("DECREMENT",value)   // }   addNumOdd(context,value){       if(context.state.totalNum % 2){           context.commit("ADDNUMBER",value)       }   },   addWait(context,value){       setTimeout(() => {           context.commit("ADDNUMBER",value)       },500)   },   addPersonWang(context,value){       if(value.name.indexOf('王') === 0){           context.commit('ADD_PERSON',value)       }else{           alert("请输入姓王的人")       }   }
}
//准备 mutations--用于操作数据
const mutations = {   ADDNUMBER(state,value){       state.totalNum += value   },   DECREMENT(state,value){       state.totalNum -= value   },   ADD_PERSON(state,value){       state.personList.unshift(value)   }
}
//准备state--用于存储数据
const state = {   totalNum:0,   personList:[{id:"001",name:"张三"}]
}
​
//准备getters--用于计算state中的数据
const getters = {   bigNum(){       return state.totalNum * 10   },   firstPerson(){       return state.personList[0]   }
}
​
//创建并暴露 store
export default new Vuex.Store({   actions,   mutations,   state,   getters
})

新添加了一个 Persons组件,我们发现 store中的代码变得越来越多,所以我们可以把它们拆成两个store,把actions、mutations、state、getters 拆分成两部分,可以继续写在 index.js中,也可以分开写在两个文件中,在index.js 中引入这两个文件

count.js 如下:

const actions = {   addNumOdd(context,value){       if(context.state.totalNum % 2){           context.commit("ADDNUMBER",value)       }   },   addWait(context,value){       setTimeout(() => {           context.commit("ADDNUMBER",value)       },500)   },       
}
const mutations = {   ADDNUMBER(state,value){       state.totalNum += value   },   DECREMENT(state,value){       state.totalNum -= value   },
}
const state = {   totalNum:0
}
const getters = {   bigNum(){       return state.totalNum * 10   },
}
export default {   namespaced:true,   actions,   mutations,   state,getters
}

person.js 如下

const actions = {   addPersonWang(context,value){       if(value.name.indexOf('王') === 0){           context.commit('ADD_PERSON',value)       }else{           alert("请输入姓王的人")       }   }
}
const mutations = {   ADD_PERSON(state,value){       state.personList.unshift(value)   }
}
const state = {   personList:[{id:"001",name:"张三"}]
}
const getters = {   firstPerson(){       return state.personList[0]   }
}
export default {   namespaced:true,   actions,   mutations,   state,getters
}

在这两个新的js文件中,可以看到多了一个东西是 namespaced,就是命名空间,设置值为true。默认该值是false,如果不设置为 true,在组件中传入的配置名是识别不到的

在 index.js中

//该文件用于创建Vuex中最核心的Store
​
//引入Vue
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//使用vuex 插件
Vue.use(Vuex)
​
import countAbout from './count'
import personAbout from './person'
​
//创建并暴露 store
export default new Vuex.Store({   modules:{       countAbout,       personAbout   }
})

引入js文件,在 创建Store 实例时,在配置项配置 modules,里面的值是 引入的对象

 

在组件中使用分为两种情况

  • 使用mapxxx方法生成

    <script>
    import {mapState,mapGetters,mapActions,mapMutations} from 'vuex'
    export default {   name:'Counts',   data(){       return{           selectNum:1       }    },   computed:{       ...mapState('countAbout',['totalNum']),       ...mapGetters('countAbout',['bigNum'])   },   methods:{       ...mapActions('countAbout',['addNumOdd','addWait']),       ...mapMutations('countAbout',['ADDNUMBER','DECREMENT'])   }
    }
    </script>

    在引用 State、Getters、Actions、Mutations时,前面要传入一个参数,就是你在创建Store时配置的对象名,如果namespaced设置为false,那么这里传入的参数就识别不到,在 模板中只能用countAbout.xxx去使用数据了

  • 使用 this.$store.xxx

    <script>
    import {nanoid} from 'nanoid'
    export default {   name:'Persons',   data(){       return{           personName:''       }   },   computed:{       personList(){           return this.$store.state.personAbout.personList       },       firstPerson(){           return this.$store.getters['personAbout/firstPerson']       },       counts(){           return this.$store.state.countAbout.totalNum       }   },   methods:{       addPerson(){           const person = {id:nanoid(),name:this.personName}           this.$store.commit('personAbout/ADD_PERSON',person)           this.personName = ''       },       addPersonWang(){           const person = {id:nanoid(),name:this.personName}           this.$store.dispatch('personAbout/addPersonWang',person)           this.personName = ''       }   }
    }
    </script>
    • 引入 state 时,使用 this.$store.state.personAbout.personList

    • 引入getters 时,使用 this.$store.getters['personAbout/firstPerson']

    • 调用dispatch时,this.$store.dispatch('personAbout/addPersonWang',person)

    • 调用commit时,this.$store.commit('personAbout/ADD_PERSON',person)

    getters、dispatch、commit 都需要使用 namespaced/xxx的方式

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

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

相关文章

27-String类

String字符串是常量,创建之后不可改变 字符串字面值存储在字符串池中,可以共享 String s = "hello"; 产生一个对象,字符串池中存储 String s = new String("hello");//产生两个对象,堆、池各存储一个String name = "hello";//"hello…

01字典树和可持久化01字典树

01字典树 01字典树是一种只有0和1两种边的字典树。可以解决查询第 \(k\) 小,查询 \(x\) 是第几小等问题。 查询第 \(k\) 小 可以把输入的数转成等长二进制,然后插入01字典树。比如将 \([0,0,1,3,3]\) 插入字典树:这里红色数字表示以该段为前缀的数的个数,黑色表示对应的数。…

c# , net 创建树形结构,创建树形节点

/// <summary> /// 生成树形结构 /// </summary> public void GetTreeNode() {//SqlHelper.GetSqlDataReader是封装的查询数据库语句,可根据自己需求封装//假设获取所有一级节点List<Products> products = SqlHelper.GetSqlDataReader(sql);for (int i = 0; …

abc360 E 题解

E 对于位置2~n,它们的概率是相等的。 n*n个(x,y)对。其中x可以等于y。对于x/y,y的逆元rev(y)为mul(y,mod-2)。 加、减、乘、除都可以做。比如48/9和16/3的结果是一样的,48*rev(9)%mod = 16*rev(3)%mod。比如3*rev(2)%mod = (rev(2)+rev(2)+rev(2))%mod.对于每次操作,有多少…

数业智能荣登「全球应用算法模型大赛50强」

近日,由上海市经济和信息化委员会、上海市普陀区人民政府,上海市人工智能行业协会主办,上海人工智能研究院等单位联合承办的《BPAA第四届全球应用算法模型典范大赛》经过一个多月的角逐,最终公布《BPAA第四届全球应用算法模型典范大赛TOP50榜单》。数业智能心大陆凭借独立自…

快速调用 GLM-4-9B-Chat 语言模型

一、确认本机显卡配置二、下载大模型 国内可以从魔搭社区下载, 下载地址:https://modelscope.cn/models/ZhipuAI/glm-4-9b-chat/files 三、运行官方代码import torch from transformers import AutoModelForCausalLM, AutoTokenizerdevice = "cuda"tokenizer = A…

戴尔服务器SQL server数据恢复

服务器数据恢复环境: 一台Dell服务器,共有10块硬盘,配置了raid5磁盘阵列,操作系统:linux,里面存有SQL server数据库。服务器数据恢复故障检测分析: 服务器在正常运行过程中,对服务器进行重装系统操作,操作成功后发现服务器的磁盘分区与原来不同,其中一个分区丢失,其…

网络安全:Nginx安全问题使1400多万台服务器容易受到ddos攻击

据外媒报道,近日 nginx 被爆出存在安全问题,有可能会致使 1400 多万台服务器易遭受 DoS 攻击。 而导致安全问题的漏洞存在于 HTTP/2 和 MP4 模块中。 新版本的Nginx Web服务器已于11月6日发布,用于修复影响1.15.6,1.14.1之前版本的多个安全问题, 该漏洞允许潜在的攻击者触发…

服务器硬盘亮红灯数据恢复

故障服务器数据恢复环境: 一台故障服务器,有3块SAS 320GB的硬盘组建的raid5磁盘阵列。 故障服务器数据恢复检测分析: 服务器运行过程中有一块硬盘的指示灯变为红色,raid5磁盘阵列出现故障,服务器上层操作系统的分区无法识别。服务器数据恢复过程: 1、将故障服务器上磁盘编…

服务器RAID5故障该如何解决

故障服务器恢复环境: 一台HP LH6000的服务器,4块18GB的硬盘做成RAID5磁盘阵列,操作系统为Window 2000,数据库是Server 2000。 故障服务器检测分析: 故障服务器经检测发现,一块硬盘红灯闪亮,机器还在正常运行,但没有多久,系统就不能正常运行,这时才发现另一块硬盘的红…

存储断电导致虚拟机无法启动

故障存储虚拟机环境: 一台VMware虚拟机无法启动(虚拟机中存储了oracle数据库)。故障存储虚拟机检测分析: 发生故障的存是由于机房意外断电导致,清空cache并尝试重新启动该虚拟机但失败。需要对该存储进行数据恢复。 故障虚拟机数据恢复流程: 1.合并虚拟机快照(因虚拟机中…

振弦采集仪在岩土工程监测中的优点与应用

振弦采集仪在岩土工程监测中的优点与应用 河北稳控科技振弦采集仪是一种常用的岩土工程监测仪器,通过测量振弦的振动频率和振幅,可以得到土体的力学特性参数,从而对土体的变形和稳定性进行分析和评估。振弦采集仪具有一些优点,同时在岩土工程的监测中有着广泛的应用。 第一…

程序员悠闲的一天{苏州周末休闲文化1日游

随便写写,平时很忙,苏州,都是姑苏区、园区、吴中区活动的比较多,因为外地朋友来了,他们想去相城区,那就出发吧。明天继续回去写代码搬砖了。拍照技术不行凑合看吧。

冗余组典型配置举例

1、组网需求工作在三层,上下行分别连接两台路由器,两台路由器接口不在同一网段如图所示,Device A和Device B组成IRF,Router 1和IRF相连的接口与Router 2和IRF相连的接口不在同一网段,Router 3和IRF相连的接口与Router 4和IRF相连的接口不在同一网段。 正常情况下,流量走R…

git 通过ssh 拉 gitlab项目代码

通过https 登录token 拉取不到 ,就用ssh吧!先查看本地git的配置 git config --list --global发现没有配置 增加配置 git config --global user.name "beckh" git config --global user.email "自己的邮箱" 生成密钥 ssh-keygen -t rsa -C "自己邮箱…

java实现微信登录

上一篇做了php的微信登录,所以也总结一下Java的微信授权登录并获取用户信息这个功能的开发流程。前言 上一篇做了php的微信登录,所以也总结一下Java的微信授权登录并获取用户信息这个功能的开发流程。 配置 配置什么的就不多说了,详细的配置可以直接前往我上一篇查看。 http…

程序员的零食好物:十分米莲藕汁 写代码头秃

今日种草打卡一件办公室清爽养生饮料十分米饮品 宠粉福利店铺 :某信小程序:十分米生活馆 抖店:十分米当夏日的热浪如潮水般汹涌而来,你是否渴望一种能瞬间驱散酷暑、唤醒味蕾的神奇饮品? 今天,我要为你介绍的,就是这样一款清凉解暑的秘密武器——十分米莲藕汁宝应。 它不…

SpringBoot+mail 轻松实现各类邮件自动推送

一、简介 在实际的项目开发过程中,经常需要用到邮件通知功能。例如,通过邮箱注册,邮箱找回密码,邮箱推送报表等等,实际的应用场景非常的多。 早期的时候,为了能实现邮件的自动发送功能,通常会使用 JavaMail 相关的 api 来完成。后来 Spring 推出的 JavaMailSender 工具,…

fastjson低版本反序列化bug/设计缺陷记录

1. 问题场景 _id正常的赋值 相同的代码我们继续跑 _id的值被反序列化到id上了??? 相同的代码,跑出不一样的反序列化结果,amazing 2.问题探究 2.1 List<FieldInfo> 反序列化时会先创建一个List<FieldInfo>每一个FieldInfoList<FieldInfo>的填充方式:遍历…