Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的全部组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。html
初学vuex,读完这段官方定义之后,黑人问号,感受每一个字都认识,可是合在一块了,好像就不理解了。好叭,让咱们用大白话翻译一下。补充:官方文档定义一个概念的时候,的确是要作到表述凝练简洁,因此就会出现这样的定义概念略有晦涩的状况
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式vue
vuex是为vue.js项目开发的一个插件(包),这个插件(包)主要就是用来作
状态管理
的。vuex问:什么是状态管理,状态管理就管理状态的(好像是废话),其实在开发中,有一个比较常听到的词就是状态,何为状态?咱们知道灯泡开和关分别是一种固定状态,咱们可用1表明开,0表明关。这样的话,用数字就能够表明状态了,那反过来讲,状态就是数据的具体表现形式,因此咱们能够这样理解:状态管理就是数据管理,进一步而言,vuex就是去管理vue中的数据的npm
它采用集中式存储管理应用的全部组件的状态后端
鲁迅说:vue是组件化开发,就是把一个页面拆分红一小块一小块。每一小块都要有本身的数据用来呈现。好比下拉框有下拉框供选择的数据,表格有表格要呈现的数据。那么这些数据能够直接放在.vue文件中的data里面去管理,可是若是是大项目的话,数据放在.vue中的data去管理略有欠缺。因此:可使用vuex去统一存放管理各个组件的数据。vuex就像一个仓库,用来存放组件中须要用到的数据,至于管理,就是增删改查,往vuex中存取、修改、删除等操做
并以相应的规则保证状态以一种可预测的方式发生变化数组
这句话的意思就是,想要存取、修改、删除vuex仓库中的状态数据,须要按照必定的语法规则,好比按照 action--> mutaion--> state的规则去增删改查,好比使用辅助函数如增删改查vuex中的数据。这个具体的规则下文中的vuex使用步骤中会逐一讲解
因此vuex就是一个仓库,用来存放数据的。因此咱们使用vuex通常会新建一个store文件夹,store单词的中文意思就是商店、仓库的意思框架
首先要搭建好项目,搭建项目的过程不赘述,项目搭建好了,咱们就能够按照以下步骤使用vuex了
由于vuex是特定的用来管理vue中的数据的一款插件,因此按照可插拔框架的思想,想要使用vuex就下载安装,不想用的时候就卸载便可npm install vuex --save
异步
以下图:ide
把store对象挂载到vue对象上面的话,那么每一个组件均可以访问到这个store对象了,那么每一个组件都能去使用vuex了
既然vue的总实例上挂载的vuex的$store对象中有咱们定义的state、mutations、actions、getters,那么咱们经过this.$store...就能够在各个组件上访问、使用vuex中数据了。这么一来,就验证了vuex文档中的那句话:vuex采用集中式存储管理应用的全部组件的状态
是啊,都集中在vue实例上了,全部组件的状态均可以访问到了。模块化
其实学习vuex就是学习两点:
- 如何读取vuex中仓库的数据
- 如何修改vuex中仓库的数据
在上述代码中,咱们已经在vuex中的state里面定义了一个msg属性,再贴一下代码
export default new Vuex.Store({ state:{ msg:'我是vuex哦' }, // 等... })
接下来咱们在组件中使用这个数据,并呈如今页面上
<h2>{{this.$store.state.msg}}</h2>
方式一不太优雅,通常不用,主要用方式二或方式三
<template> <div class="box"> <h2>{{msg}}</h2> </div> </template> <script> export default { data() { return { msg:'' } }, mounted() { this.msg = this.$store.state.msg }, } </script>
<template> <div class="box"> <h2>{{msg}}</h2> </div> </template> <script> export default { computed: { msg(){ return this.$store.state.msg } } } </script>
通常是在事件的回调函数中去修改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的规则是什么呢?请看下图
咱们先看一下官方给到的图解
看完上图之后,咱们能够总结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记录下来)
组件中若是不是异步发请求去更改数据,也能够直接跳过actions,直接让仓库管理员mutations去修改数据,不过这种方式不是太多
代码以下
// 组件 <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中咱们能够定义一个函数,这个函数咱们用来修改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.msg一、this.$store.state.msg二、this.$store.state.msg3等
。为了简化,vuex内部封装了四个辅助函数,分别用来对应state,mutations,actions,getters的操做。辅助函数,简而言之,就是尤大佬封装的语法糖
辅助函数通常搭配计算属性和方法使用
第一步,假设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>
第五步,页面效果图以下
使用方法和mapState基本同样
computed:{ ...mapGetters(['msg']), }
好比,咱们在按钮点击事件的回调函数中去触发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的用法和mapMutations的用法基本上同样,就换个单词便可,在此不赘述...mapActions(["sss"])
意思是:去触发Actions中的sss函数
提起模块化,思想仍是那句话,大而化小,便于管理。不少语言都有模块化的应用,vuex也是同样。试想,若是全部的状态数据都写在一块儿,看着容易眼花缭乱,不便于管理。因此尤大老对于vuex的设计中,就作了模块化module的处理
这里以获取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对象,就能够看到对应的值
这里以触发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>
注意,上述我使用vuex的模块化module的时候,没有加上命名空间namespace
,因此去提交对应模块下的mutations的时候,能够直接写this.$store.commit('moduleChange','我是参数')
或...mapMutations(['moduleChange'])
这样的话,vuex会去本身全部模块下去找moduleChange
这个函数,而后去修改。这样的话,略微浪费性能,由于,默认状况下,vuex模块内部的 action、mutation 和 getter 是挂载注册在 全局命名空间的,这样使得多个模块可以对同一 mutation 或 action去操做,就不停的找,直到找到为止。可是通常状况下,咱们使用vuex模块化的时候都会加上命名空间,作到独立、复用。接下来咱们说一下,vuex模块化的标准用法,即加上命名空间的用法
// 不使用辅助函数 moduleChange(){ this.$store.commit('vue/moduleChange'); // 以斜杠分割,斜杠前写对应模块名,斜杠后写对应mutations中的方法名 } // 使用辅助函数 ...mapMutations('vue',['moduleChange']) // 以逗号分割,逗号前写模块名,逗号后是个数组,数组中放置对应mutations中的方法名 //3.别名状态下 ...mapMutations({ anotherName:'vue/moduleChange' // 和不使用辅助函数同样 }),
让咱们还回到vuex官网下定义的那句话:
Vuex 是一个专为 Vue.js 应用程序开发的**状态管理模式**。它采用集中式存储管理应用的全部组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化
貌似这样定义还挺好的,科学严谨...
最后一首打油诗送给各位看官,娱乐一下,哈哈
《码破苍穹》码宗强者名尤大代码化翼走天下随手祭出VUE恐怖如斯真可怕笔者码渣虽技薄但却心中有梦呀还望各位大佬们点赞鼓励一下哈