Vue--》详解状态管理工具——Vuex
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
目录
vuex
专门在Vue中实现集中式状态(数据)管理的一个Vue插件对vue应用中多个组件的共享状态进行集中式的管理(读/写)也是一种组件间通信的方式且适用于任意组件间通信。vuex的应用场景是多个组件依赖于同一状态、来自不同组件行为需要变更同一状态。说白了就是想共享
其官方文档为vuex 其工作原理图如下图所示Vuex中的三个函数都是在同一个仓库store里面的actions一般用于发送Ajax请求当然日常开发中如果没有特别的要求actions也可以省略而让数据去直接访问mutations也是可以的。
搭建vuex环境
在2022年2月7日vue3成为默认版本vue3成为默认版本的同时vuex也更新到4版本而vuex的最新版本只支持vue3项目如果想在vue2中使用vuex需下载vuex3版本。
在Vue2项目中使用vuex安装命令如下
npm install vuex@3
创建文件src/store/index.js
// 该文件用于创建 Vuex 中的核心store
// 引入 Vue
import Vue from 'vue'
// 引入 Vuex
import Vuex from '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中传入 store 配置项
vuex的使用
我们可以将求和的sum放置在vuex中的state中将该值设置为共享即写在vm上。代码如下
<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="increment">+</button>
<button @click="decrement">-</button>
<button @click="incrementOdd">当前求和为奇数再加</button>
<button @click="incrementWait">等一等再加</button>
</div>
</template>
<script>
export default {
name:'Count',
data(){
return {
n:1 // 用户选择数字
}
},
methods:{
increment(){
this.$store.dispatch('jia',this.n)
},
decrement(){
this.$store.dispatch('jian',this.n)
},
incrementOdd(){
if(this.$store.state.sum % 2){
this.$store.dispatch('jia',this.n)
}
},
incrementWait(){
setTimeout(()=>{
this.$store.dispatch('jia',this.n)
},1000)
}
}
}
</script>
<style lang="less" scoped>
button{
margin-left: 5px;
}
</style>
// 该文件用于创建 Vuex 中的核心store
// 引入 Vue
import Vue from 'vue'
// 引入 Vuex
import Vuex from 'vuex'
// 使用插件
Vue.use(Vuex)
// 准备actions——用于响应组件中的动作
const actions = {
jia(context,value){
// console.log('actions中的jia被调用了');
context.commit('JIA',value)
},
jian(context,value){
// console.log('actions中的jia被调用了');
context.commit('JIAN',value)
}
}
// 准备mutations——用于操作数据state
const mutations = {
JIA(state,value){
state.sum+=value
},
JIAN(state,value){
state.sum-=value
}
}
// 准备state——用于存储数据
const state = {
sum:0, // 当前的和
}
// 创建并导出store
export default new Vuex.Store({
actions,
mutations,
state,
})
当然我们也可以将条件逻辑直接写到actions里面即可如下
actions中的一些基础函数也可以省略而让数据直接去操控mutations如下
vuex开发者工具使用
vuex和vue开发者工具都是整合到一起的所以不需要在下载工具直接使用vue开发者工具即可
我们点击按钮Vuex会监听到你当前执行的函数以及数据发生的时间及其变化。
getters
有时候我们需要从 store 中的 state 中派生出一些状态如果有多个组件需要用到此属性我们要么复制这个函数或者抽取到一个共享函数然后在多处导入它——无论哪种方式都不是很理想。Vuex 允许我们在 store 中定义“getter”可以认为是 store 的计算属性。
mapState和mapGetters
mapState方法用于帮助我们映射 state 中的数据为计算属性
computed:{
// 程序员自己手写
name(){
return this.$store.state.name
},
age(){
return this.$store.state.age
},
// 程序员借助vuex提供的方法 mapState 生成计算属性对象写法
...mapState({name:'name',age:'age'}),
// 程序员借助vuex提供的方法 mapState 生成计算属性数组写法
...mapState(['name','age'])
},
mapGetters方法用于帮助我们映射getters中的数据为计算属性
computed:{
// 程序员自己手写
bigSum(){
return this.$store.getters.sum
},
// 程序员借助vuex提供的方法 mapState 生成计算属性对象写法
...mapGetters({bigSum:'bigSum'}),
// 程序员借助vuex提供的方法 mapState 生成计算属性数组写法
...mapGetters(['bigSum']),
},
mapMutations和mapActions
mapMutations与mapActions使用时若需要传递参数需要在模板中绑定事件时传递好参数否则参数是事件对象。
mapMutations用于帮助我们生成与 mutations 对话的方法即包含$store.commit(xxx)的函数
methods:{
// 程序员自己手写
increment(){
this.$store.commit('JIA',this.n)
},
decrement(){
this.$store.commit('JIAN',this.n)
},
// 使用 mapMutations 方法简化方法书写对象方式
...mapMutations({increment:'JIA',decrement:'JIAN'}),
// 使用 mapMutations 方法简化方法书写数组方式
...mapMutations(['JIA','JIAN']),
}
使用对象方式点击事件调用函数时需要将指定的用户选择增加的数字作为形参传入
使用数组方式点击事件调用函数时名称需要和数组中的元素保持一致
mapActions用于帮助我们生成与actions对话的方法即包含$store.dispatch(xxx)的函数
methods:{
// 程序员自己手写
incrementOdd(){
this.$store.dispatch('jiaOdd',this.n)
},
incrementWait(){
this.$store.dispatch('jiaWait',this.n)
},
// 使用 mapActions 方法简化方法书写对象方式
...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'}),
// 使用 mapActions 方法简化方法书写数组方式
...mapActions(['jiaOdd','jiaWait'])
}
和mapMutations方法类似使用对象形式也需要传入需要将指定的用户选择增加的数字作为形参传入
和mapMutations方法类似使用数组方式点击事件调用函数时名称需要和数组中的元素保持一致
多组件共享数据
当我们想进行多组件共享时将要共享的数据写到 state 里面
创建person组件来获取公共是数据person
<template>
<div>
<h1>人员列表</h1>
<h2>Count组件的求和为{{sum}}</h2>
<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 {
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>
因为personList是写到公共数据上即为共享数据想用的组件之间用mapState调用即可
调用完直接引用即可
其具体实现过程如下
vuex实现模块化
在大型项目中如果想使用vuex肯定不可能将所有的配置都写在一起因为这样难免会发生冲突所以就需要对vuex进行模块化如下
两者的vuex结果给出如下给与书写规范参考
// 共享数值数据
const countOptions = {
// 开启命名空间
namespaced: true,
// 准备actions——用于响应组件中的动作
actions:{
jiaOdd(context,value){
if(context.state.sum % 2){
context.commit('JIA',value)
}
},
jiaWait(context,value){
setTimeout(()=>{
context.commit('JIA',value)
},500)
}},
// 准备mutations——用于操作数据state
mutations:{
JIA(state,value){
state.sum+=value
},
JIAN(state,value){
state.sum-=value
},
},
// 准备state——用于存储数据
state:{
sum:0, // 当前的和
name:'张三',
age:18,
},
// 准备getters用于将state中的数据进行加工
getters:{
bigSum(state){
return state.sum*20
}
}
}
// 共享人员数据
const personOptions = {
namespaced:true,
actions:{
addPersonName(context,value){
if(value.name.indexOf('王')===0){
context.commit('ADD_PERSON',value)
}else{
alert('添加的人必须姓王')
}
},
addPersonAxiosName(context){
axios.get('https://api.uixsj.cn/hitokoto/get?type=social').then(
response=>{
context.commit('ADD_PERSON',{id:nanoid(),name:response.data})
},
err=>{
alert(err.message)
}
)
}
},
mutations:{
ADD_PERSON(state,value){
state.personList.unshift(value)
}
},
state:{
personList:[
{id:'001',name:'张三'}
]
},
getters:{
firstPersonName(state){
return state.personList[0].name
}
}
}
我们将vuex进行模块化分组那么调用这个共享的数据的方法肯定不能和之前的一样了要进行一定的变化不知道有没有发现我们在进行模块化分组的时候是需要使用命名空间 namespace 的配置项这种重点调用共享数据方式如下
如果不想使用vuex内置的函数方法单纯的从vm上一层层的调用模块化后的数据的话它的书写方式也和一般方式不同如下
当然我们调用methods方法时也是一致的