什么是vuex
官方定义
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
大白话讲解
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式
它采用集中式存储管理应用的所有组件的状态
并以相应的规则保证状态以一种可预测的方式发生变化
所以vuex就是一个仓库,用来存放数据的。所以我们使用vuex一般会新建一个store文件夹,store单词的中文意思就是商店、仓库的意思
vuex的应用场景
- 正常数据放到data里面就行了,免得麻烦,一般小项目都很少用到vuex,毕竟vuex的步骤稍微多一点
- 一般公共数据放到vuex中会比较好,毕竟组件有自己的data可以存放数据,公共的变量如用户信息、token等。vuex存一份,localstorage再存一份,取数据直接从vuex里面取,取不到再从localstorage里面去取。
- 跨很多组件层级的数据通信,也可以通过vuex去做管理,毕竟vuex就像一个对象一个,好多组件都指向这个对象,当这个vuex对象发生了变化,所有的组件中对应的内容都会发生变化,这样就能做到实时响应,一个变,大家都变
使用步骤
第一步 npm下载安装vuex插件
因为vuex是特定的用来管理vue中的数据的一款插件,所以按照可插拔框架的思想,想要使用vuex就下载安装,不想用的时候就卸载即可npm install vuex --save
第二步 新建store文件夹注册使用vuex插件
如下图:
打印的vue实例对象如下图
看一下$store的上具体内容
既然vue的总实例上挂载的vuex的$store对象中有我们定义的state、mutations、actions、getters,那么我们通过this.$store...就可以在各个组件上访问、使用vuex中数据了。这么一来,就验证了vuex文档中的那句话:vuex采用集中式存储管理应用的所有组件的状态
是啊,都集中在vue实例上了,所有组件的状态都可以访问到了。
第三步 读取vuex中仓库的数据
在上述代码中,我们已经在vuex中的state里面定义了一个msg属性,再贴一下代码
export default new Vuex.Store({
state:{
msg:'我是vuex哦'
},
// 等...
})
接下来我们在组件中使用这个数据,并呈现在页面上
方式一 双括号表达式直接使用(不推荐)
<h2>{{this.$store.state.msg}}</h2>
方式一不太优雅,一般不用,主要用方式二或方式三
方式二 mounted中去取用vuex中的数据
<template>
<div class="box">
<h2>{{msg}}</h2>
</div>
</template>
<script>
export default {
data() {
return { msg:'' }
},
mounted() {
this.msg = this.$store.state.msg
},
}
</script>
方式三 使用computed去取vuex中的数据
<template>
<div class="box">
<h2>{{msg}}</h2>
</div>
</template>
<script>
export default {
computed: {
msg(){ return this.$store.state.msg }
}
}
</script>
第四步 修改vuex中的数据
一般是在事件的回调函数中去修改vuex中的数据,比如我们点击一个按钮,去修改vuex中的数据
方式一 直接修改(不推荐)
<template>
<div class="box">
<h2>{{msg}}</h2>
<el-button @click="changeVuex">修改</el-button>
</div>
</template>
<script>
export default {
methods: {
// 直接赋值修改vuex中的state的数据
changeVuex(){
this.$store.state.msg = '修改vuex'
},
},
computed: {
msg(){ return this.$store.state.msg }
}
}
</script>
这种方式勉强能用,不过vuex当开启了严格模式的时候,就会报错,开启严格模式代码如下:
export default new Vuex.Store({
strict:true, // 开启严格模式
state:{
msg:'我是vuex哦'
},
// 等...
})
报错信息图如下:
报错信息含义Error:[vuex] do not mutate vuex store state outside mutation handlers.
不要不通过mutation的操作就去修改vuex中store里面的state状态值
所以由此我们就想到了vuex定义的那句话:并以相应的规则保证状态以一种可预测的方式发生变化
这里的相应的规则
就是指,想要修改vuex中的数据,就要按照vuex中操作数据的步骤流程规则来,嘿嘿,要不然就给你报错。那么vuex定义的修改state的规则是什么呢?请看下图
方式二 action-->mutation-->state
我们先看一下官方给到的图解
看完上图以后,我们可以总结vuex的使用规则如下
组件想要去更改vuex中的数据,但是组件自己只是口头传唤一下actions干活,即:dispatch一下actions
(组件说:嘿,actions,我要更改vuex中的数据了,你发个请求,从后端接口中拿到我要的数据去更改一下)
action得到消息后,就会向后端发请求,获取到后端返回的数据,action拿到后端返回的数据以后,就把数据commit提交给mutations,即:commit一下mutations
(actions拿到数据以后,但是也比较懒,把数据交给仓库管理员mutations,告知要更改对应数据以后,就撤了)
mutations相当于最终的仓库管理员,由这个仓库管理员去修改vuex仓库中的数据,即:mutate一下state
(mutations任劳任怨,就去更改vuex中state的数据,更改完以后,就等待下一次的干活,mutations修改数据的过程,会被仓库的监控,也就是vue的开发工具devTool记录下来)
- 而vue数据是响应式的,仓库数据一改变,对应使用仓库数据的组件就会重新render渲染,所以页面效果也就改变了
代码如下
// 组件
<template>
<div class="box">
<h2>{{msg}}</h2>
<el-button @click="changeVuex">修改</el-button>
</div>
</template>
<script>
export default {
methods: {
changeVuex(){
this.$store.dispatch('actionsChange')
},
},
computed: {
msg(){ return this.$store.state.msg }
}
}
</script>
// vuex
export default new Vuex.Store({
strict:true,
state:{
msg:'我是vuex哦'
},
mutations:{
// 这里第一个形参state就是仓库state,是可以访问到state里的msg的值,即 可以修改state
// 第二个形参params是actions中传过来的数据
mutationsChange(state,params){
console.log(state,params);
state.msg = params
}
},
actions:{
// 这里的形参store对象下面有commit方法
// 可以去告知对应的mutations中的函数执行
actionsChange(store){
console.log(store);
setTimeout(() => {
store.commit('mutationsChange', '规范修改vuex')
}, 500);
}
}
})
效果图如下
devtool记录mutations的操作
补充getter加工
getter中我们可以定义一个函数,这个函数我们用来修改state中的值的,函数接收一个参数state,这个state参数就是当前的state对象,通过这个参数可以加工state中的数据,加工好return出去,以供组件中使用
// vuex
export default new Vuex.Store({
strict:true,
state:{
msg:'我是vuex哦'
},
getters:{
gettersChange(state){
return state.msg + '---getter修改state中的数据'
}
},
})
组件中使用的时候,就直接使用getter中的数据即可,如下:this.$store.getters.gettersChange
当然也可以不用getter,就是在组件中取到vuex中的数据以后,我们再进行加工。不过能在getter中加工的最好就在getter中加工,因为这样写代码,比较优雅
辅助函数
函数函数的出现,就是为了让我们能少写几行代码,我们以获取vuex中state为例,假设我们在一个组件中需要获取多个state中的值,这样的话这个语句就要写多次,this.$store.state.msg1、this.$store.state.msg2、this.$store.state.msg3等
。为了简化,vuex内部封装了四个辅助函数,分别用来对应state,mutations,actions,getters的操作。辅助函数,简而言之,就是尤大佬封装的语法糖
mapState辅助函数
第一步,假设vuex仓库中有三个数据,我们需要在组件上使用这三个数据
// store.js
export default new Vuex.Store({
state:{
msg1:'辅助函数一',
msg2:'辅助函数二',
msg3:'辅助函数三',
},
}
第二步,从vuex插件中引入辅助函数import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'
第三步,在计算属性中使用辅助函数mapstate取到state中的数据
// 方式一,数组形式
computed: {
...mapState(['msg1','msg2','msg3'])
},
// 方式二, 对象形式(vuex模块化比较常用)
computed: {
...mapState({
msg1: state=>state.msg1,
msg2: state=>state.msg2,
msg3: state=>state.msg3,
})
},
第四步,在组件中直接就可以在差值表达式中使用了
<template>
<div>
<h1>{{msg1}}</h1>
<h2>{{msg2}}</h2>
<h3>{{msg3}}</h3>
</div>
</template>
第五步,页面效果图如下
mapGetters辅助函数
使用方法和mapState基本一样
computed:{
...mapGetters(['msg']),
}
mapMutations辅助函数
比如,我们在按钮点击事件的回调函数中去触发mutations,对比一下,不用辅助函数和用辅助函数的语法书写区别
vuex结构
mutations:{
kkk(state,params){
state.msg = params
}
},
html结构
<template>
<div>
<h2>{{ msg }}</h2>
<el-button @click="kkk('我是参数')">辅助函数mapActions</el-button>
</div>
</template>
js代码
<script>
import { mapState, mapMutations } from "vuex";
export default {
computed: {
...mapState(["msg"]),
},
methods: {
// 不使用辅助函数的写法
kkk(params) {
this.$store.commit("kkk", params);
},
// 使用辅助函数的写法
...mapMutations(["kkk"]),
},
};
</script>
注意:使用辅助函数,貌似没有地方传参,实际是辅助函数帮我们默默的传递过去了,这个参数需要写在html结构中的点击语句中,如上述代码:<el-button @click="kkk('我是参数')">辅助函数mapActions</el-button>
mapActions辅助函数
mapActions的用法和mapMutations的用法基本上一样,就换个单词即可,在此不赘述...mapActions(["sss"])
意思是:去触发Actions中的sss函数
vuex的module模块化
提起模块化,思想还是那句话,大而化小,便于管理。很多语言都有模块化的应用,vuex也是一样。试想,如果所有的状态数据都写在一起,看着容易眼花缭乱,不便于管理。所以尤大老对于vuex的设计中,就做了模块化module的处理
图解步骤
在组件中使用vuex模块化
获取vuex模块中的数据
这里以获取state中的数据为例,获取getters中的数据写法基本一样,不赘述
<template>
<div>
<h2>{{ msg }}</h2>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: "CodeVue",
computed: {
// 正常方式
msg(){
return this.$store.state.vue.module// 找state里的vue模块下的module的值
},
// 使用辅助函数方式,这里用对象的写法
...mapState({
msg:state=>state.vue.module// 找state里的vue模块下的module的值
})
}
};
</script>
打印store对象,就可以看到对应的值
修改vuex模块中的数据
这里以触发mutations为例,actions写法基本一致,不赘述
不使用辅助函数
<template> <div> <h2>{{ msg }}</h2> <el-button @click="moduleChange">模块化修改值</el-button> </div> </template> <script> export default { name: "CodeVue", computed: { ...mapState({ msg:state=>state.vue.module }) }, methods: { moduleChange(){ // 注意,直接提交对应模块的方法即可,commit会自动找到对应vuex下的方法 this.$store.commit('moduleChange','我是参数') } }, }; </script>
使用辅助函数
<template> <div> <h2>{{ msg }}</h2> <!-- 我们在点击事件的语句中,把data中定义的参数带过去,去提交mutations --> <el-button @click="moduleChange(canshu)">模块化修改值</el-button> </div> </template> <script> import { mapState, mapMutations } from 'vuex' export default { name: "CodeVue", data() { return { canshu:'我是参数' } }, computed: { ...mapState({ msg:state=>state.vue.module }) }, methods: { ...mapMutations(['moduleChange']) }, }; </script>
命名空间
- 不加命名空间,所有的都找一遍。
- 加了的话,只去特定的模块找
- 所以使用命名空间的话,提交mutations写法就变了
写法如下
// 不使用辅助函数
moduleChange(){
this.$store.commit('vue/moduleChange'); // 以斜杠分割,斜杠前写对应模块名,斜杠后写对应mutations中的方法名
}
// 使用辅助函数
...mapMutations('vue',['moduleChange']) // 以逗号分割,逗号前写模块名,逗号后是个数组,数组中放置对应mutations中的方法名
//3.别名状态下
...mapMutations({
anotherName:'vue/moduleChange' // 和不使用辅助函数一样
}),
总结
让我们还回到vuex官网下定义的那句话:
Vuex 是一个专为 Vue.js 应用程序开发的**状态管理模式**。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化
貌似这样定义还挺好的,科学严谨...
最后一首打油诗送给各位看官,娱乐一下,哈哈
《码破苍穹》
码宗强者名尤大
代码化翼走天下
随手祭出VUE
恐怖如斯真可怕
笔者码渣虽技薄
但却心中有梦呀
还望各位大佬们
点赞鼓励一下哈