1、什么是Vuex?
在使用vue作为框架的前端项目开发中,我们经常会碰到Vuex,那么Vuex到底是什么东西呢?
根据官方文档给出的解释是:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
简单来说,Vuex就是一个状态管理的库,或者说是一个用来存放组件公共数据的仓库。
2、为什么要使用Vuex
要了解为什么要使用Vuex,那么我们就需要先来了解vue项目中组件之间的传参方式
2.1、组件之间的传参方法
父组件向子组件传参:
// 父组件传递参数
<template>
<!-- 引入子组件 -->
<son :fatherData="fatherData"></son>
</template>
<script>
import Son from "./son.vue";
export default {
components: {
Son,
},
data() {
return {
fatherData: "父组件的数据"
};
},
};
</script>
// 子组件接收参数
<template>
<div>
{{ fatherData }}
</div>
</template>
<script>
export default {
// 接收父组件传递的值
props: {
fatherData: {
type: String,
required: true,
},
},
};
</script>
子组件向父组件传参:
// 父组件
<template>
<!-- 引入子组件 -->
<div>
<son @getData="getSonData"></son>
<div>{{sonData}}</div>
</div>
</template>
<script>
import Son from "./son.vue";
export default {
components: {
Son,
},
data() {
return {
sonData:''
}
},
methods: {
// 自定义的调用方法的参数就是子组件传递过来的数据
getSonData(value) {
this.sonData = value
}
}
};
</script>
// 子组件
<template>
<div>
<button @click="toFather">子向父传参</button>
</div>
</template>
<script>
export default {
data() {
return {
sonData: '子组件的数据'
}
},
methods: {
// 使用$emit来触发父组件中的自定义事件,将子组件的数据通过$emit传递给父组件
toFather() {
this.$emit('getData',this.sonData)
}
}
};
</script>
组件之间跳转的传参方法(示例由组件A跳转到组件B):
// A组件
<template>
<button @click="toB">跳转到B页面</button>
</template>
<script>
export default {
data() {
return {
aData: "A页面的数据",
};
},
methods: {
toB() {
// 在页面跳转时,通过query传递数据
this.$router.push({
path: "/B",
query: { aData: this.aData },
});
},
},
};
</script>
// B组件
<template>
<div>{{ bData }}</div>
</template>
<script>
export default {
data() {
return {
bData: "",
};
},
created() {
this.bData = this.$route.query.aData;
},
};
</script>
从上面三种组件之间传参的方式我们可以看出,组件与组件之间传递参数实现数据共享,那么组件之间需要有一定联系,要么是父子组件,要么是有跳转的关系,才能实现数据的共享。可是在完全没有联系的组件之间,他们如何实现数据的共享呢?
要想实现完全没有联系的组件之间数据共享,我们需要先思考一个问题,什么样的数据,需要同时在几个没有联系的组件中去使用呢?
2.2、 数据共享的情景
在项目开发中,我们经常会碰到一种情景,比如说一个系统,在用户登录之后,后端会将该用户的一些数据返回给前端,如用户名,token等,而这些用户数据往往不止在一个页面中使用,可能涉及到多个相互没有联系的组件,那么在这种时候,我们就需要使用到Vuex。
3、Vuex的使用
对于一个插件的使用,我们首先需要看对应的官方文档:Vuex 是什么? | Vuex (vuejs.org)。根据文档,接下来我们来一起理解Vuex。
在Vuex中有五个属性,分别为state,getters,mutations,actions,modules,下面我们将从这五个属性来学习Vuex。
3.1、state属性:
从上面的概念我们知道,Vuex是用来存放一些共享的数据,实现状态管理的一个插件,那么,我们的这些数据要放在那里呢?
在项目目录下,我们可以找到一个名为store的文件夹,文件夹中存放一个index.js的文件
我们之后关于Vuex的一些操作,基本都会在这个文件夹下的文件中实现。
首先我们来看一下index.js文件中都有些什么
// 导入vue
import Vue from 'vue'
// 导入Vuex
import Vuex from 'vuex'
// 注册Vuex组件
Vue.use(Vuex)
// 导出Vuex.Store
export default new Vuex.Store({
state: {
},
getters: {
},
mutations: {
},
actions: {
},
modules: {
}
})
我们可以看到,index.js中的内容基本和其他的插件的使用方式一样,我们主要看Vuex.Store中的内容,我们可以看到前面讲到的五个属性就是在Vuex.Store中,而我们的数据,就会放在state中。那么,怎么使用这个数据呢,我们使用文档中举的例子来示例。
首先,我们需要在state中加入我们要在其他组件中使用的数据
// store/index.js
export default new Vuex.Store({
state: {
// 添加一个变量num
num: 0
},
})
在store中添加了数据之后,我们需要到对应的组件中使用
组件A中使用
<template>
<div>{{$store.state.num}}</div>
</template>
组件B中使用
<template>
<div>{{num}}</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
computed: {
...mapState(['num'])
}
}
</script>
在这里我举例了两种组件调用state中数据的方法,文档中还提到了其他的方法,可以自行查看。
到这里我们发现,我们已经实现了将数据存放在一个地方,可以供多个不相关的组件一起调用,那么好像数据共享就完成了一部分,但是我们也知道,前端的数据往往不是单纯地进行展示,而是需要进行操作,那么,对于Vuex中的数据,我们要怎么进行操作呢?
按照前端开发的思路,原则上只要我们获取到数据,好像就可以对数据进行操作了,我们既然通过store.state.num进行操作就可以了,按这个思路,我们可以看看是否成功?
<template>
<button @click="add">num加一</button>
</template>
<script>
export default {
methods: {
add() {
this.$store.state.num++;
}
}
}
</script>
通过试验,我们发现,页面展示的数据确实达到了想要的效果,但是通过Vue开发者工具,我们发现,Vuex的state一直都没有改变
很显然,我们不能直接通过$store.state.num来改变数据,那么我们到底需要怎么样改变数据呢?
3.2、mutations属性:
通过看Vuex的文档,我们可以在mutations属性介绍中发现这样一句话:更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。那么根据这句话,我们就可以知道,想要修改num,必须提交mutation,根据文档的使用方法,我们更改一下代码:
<template>
<button @click="add">num加一</button>
</template>
<script>
export default {
methods: {
add() {
this.$store.commit('addNum')
}
}
}
</script>
// store/index.js
export default new Vuex.Store({
state: {
// 添加一个变量num
num: 0
},
mutations: {
addNum(state) {
state.num++;
}
},
})
结果也符合预期:
那么到这里,数据的展示和操作好像都已经完成了,可是我们发现,还有三个属性都没有用到,那么这三个属性又有什么样的用处呢?
3.3、actions属性:
我们知道,在实际的项目开发中,我们会碰到很多异步操作,比较常见的就用axios请求,定时器等,那么我们对Vuex中的数据进行异步操作时是不是还是使用mutations呢?
很显然,大家看目录到这里,就知道对Vuex中的数据进行异步操作是要用到actions的,但是我们在学习mutations的时候有了解到更改 Vuex 的 store 中的状态的唯一方法是提交 mutation,那么actions是如何提交mutation的呢?
export default new Vuex.Store({
state: {
// 添加一个变量num
num: 0
},
mutations: {
addNum(state) {
state.num++;
}
},
actions: {
addNum(context) {
setTimeout(() => {
context.commit('addNum')
},1000)
}
},
})
<template>
<div>
<button @click="add">num加一</button>
<button @click="delayed">延时加1</button>
</div>
</template>
<script>
export default {
methods: {
add() {
this.$store.commit("addNum");
},
delayed() {
this.$store.dispatch("addNum");
},
},
};
</script>
我们可以看到在action中,有一个addNum方法接收了一个context参数,然后再方法中有一个定时器,定时器中通过conntext.commit调用了addNUm,看到.commit我们就会看到调用mutations时用的就是**this.store呢?我们使用console.log分别输出this.$store和context
在控制台中,我们可以看到,这两者有类似的属性,但是又不完全相同,但是,两者都有着同样的方法,那么就有可能是,context与store存在着某些联系,可以通过context.commit提交mutations。根据文档给出的解释是,Action函数接收了一个与store实例具有相同方法和属性的context对象,使我们可以通过context.commit来提交mutations。
3.4、modules属性:
modules的中文意思是模块,那么见名思意,我们可以大致理解为modules属性就是用来存放模块的。那么,在存放模块之前,就意味着我们需要现有模块。
在Vuex中,是允许我们将store分割成模块,每个模块拥有自己的state,mutations,action,getters甚至是modules,那么我们想象一下,为什么我们需要将store分割成模块呢?
我们知道,组件化开发,可以将根据功能划分组件,然后再讲组件整合在一起,这样既有利于我们分工,也增加了代码的复用性和便于后期的维护。而将store显然也是出于这样的考虑,我们知道,在一个大型的项目,需要进行状态管理的数据往往不是一两个变量,而是一个很复杂庞大的数据,如果我们将这些数据全部写到index.js文件中,那么整个文件就会显得冗余,而是可读性很低,那么这时候就需要我们将这些数据分割成不同的模块。
// store/index.js
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
},
modules: {
user,
menu,
tab
}
})
例如这样,我们就可以根据我们的需要,将user和menu的数据分割成一个模块,这样store/index.js这个文件就会显得很精简,而且也便于我们的更改。
3.5、getters属性:
getters这个属性主要用于对state中的数据进行一些数据处理,在某种程度上来说,比较像组件中的computed。这里的数据处理和上面的mutations的数据操作并不是同一个意思。
getters的数据数据处理是指将state处理之后在组件中展示,而mutations则是指在触发某些事件之后对数据进行对应的操作。
举个例子,我们现在state中的num是0,我们知道在点击事件提交mutations之后num会加1,但是我们现在希望在增加多一个变量的前提下,组件A展示的是1,组件B展示的是0,那么在这个时候,我们就需要用到getters对state的num进行数据处理
export default new Vuex.Store({
state: {
// 添加一个变量num
num: 0
},
getters: {
getAddNum(state) {
return state.num+1
}
},
mutations: {
addNum(state) {
state.num++;
}
},
actions: {
addNum(context) {
console.log("context",context)
setTimeout(() => {
context.commit('addNum')
},1000)
}
},
})
组件A:
<template>
<div>{{$store.getters.getAddNum}}</div>
</template>
这样,我们就可以达成我们的目的:
4、总结
Vuex的使用还有很多需要注意的地方,本文只是简单的理解Vuex的几个属性的使用方法。
需要注意的地方是:由于Vuex的版本升级,很多地方进行了修正(详情可以查看官方文档),本文的代码是基于"vuex": "^3.4.0"版本的,如果按本文的代码练习出现错误,请寻找对应的Vuex版本代码进行学习。
作者:天往
链接:https://juejin.cn/post/7139532600263049247
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。