一、什么是Vuex?
概念:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
简单点来说(说人话),就是实现任意组件中通信,并可以检测数据的变化。
二、Vuex原理
Vuex是集中于MVC模式中的Model层,规定所有的数据操作必须通过 action - mutation - state
的流程来进行,再结合Vue的数据视图v-moder等双向绑定特性来实现页面的展示更新。
下面看一张图来了解全过程。
简述主要方法详情:
Vue Components:Vue组件。展示页面,负责接收用户操作等交互行为,执行dispatch方法触发对应action进行回应。
dispatch:操作行为触发方法。是唯一能执行action的方法。
actions:操作行为处理模块。处理Vue Components接收到的所有交互行为。包含同步/异步操作,支持多个同名方法,按照注册的顺序依次触发。向后台API请求的操作就在这个模块中进行,包括触发其他action以及提交mutation的操作。该模块提供了Promise的封装,以支持action的链式触发。
commit:状态改变提交操作方法。对mutation进行提交,是唯一能执行mutation的方法。
mutations:状态改变操作方法。是Vuex修改state的唯一推荐方法,其他修改方式在严格模式下将会报错。该方法只能进行同步操作,且方法名只能全局唯一。操作之中会有一些hook暴露出来,以进行state的监控等。
state:页面状态管理容器对象。集中存储Vue components中data对象的零散数据,全局唯一,以进行统一的状态管理。页面显示所需的数据从该对象中进行读取,利用Vue的细粒度数据响应机制来进行高效的状态更新。
总的一句话简述就是:
Vue组件接收交互行为,调用dispatch方法触发action相关处理,若页面状态需要改变,则调用commit方法提交mutation修改state,通过getters获取到state新值,响应数据或状态给Vue 组件,界面随之更新。
三、Vuex的使用
1.安装
npm install vuex --save
2.新建一个文件夹store,创建inde.js
随便叫啥,随便建不建立文件夹。为了规范。
importVuefrom'vue'importVuexfrom'vuex'Vue.use(Vuex)//准备actions---用于响应组件中的动作constactions={}//准备mutations---用于操作数据(state)constmutations={}//准备state---相当于data,用于存储数据conststate={}//实例化创建并导出storeexportdefaultnewVuex.Store({namespaced:true,//解决模块命名冲突actions,mutations,state,})
注意:
我们在这一步创建index.js文件的时候导入并引用Vuex,因为我们要实例化Vuex对象。如果在main引入,会导致在main.js导入store的时候报错。
3.在main.js中引入上一步的index.js,并在实例化 Vue对象时加入 store 对象 :
importstorefrom'./store/index'//引入写好的store.....newVue({el:'#app',router,store,//使用storetemplate:'',components:{App}})
ok,环境搭好,开始操作。
4.简单使用:
先来一点简单的存放数据,取出查看。在一系列操作之后我们的VM(View Model)和VC(View component)身上都已经都有store这个数据源对象。所以我们可以从store身上使用this.$store.state.xxx
获取数据。
在index.js中准备数据
conststate={name:'浪漫主义码农',age:18,}
在组件中获取数据
<template><div>我放在store中的数据是{{this.$store.state.name}},{{this.$store.state.age}}</div></template>
5.mutation、anction
在知道每一个vm和vc身上都有store就可以好好操作了。
mutation--更改store中状态的唯一方法
根据上面的原理图,我们能知道vuex中规定只能通过提交mutation的方式去更改store中的状态,包括action中的操作,也是通过提交mutation去修改。另外一点就是vuex中规定mutation中不能包含异步操作
我们来修改上面的name、age属性。
constmutations={modify_age(state){//不带参数修改age属性,state是默认的参数state.name="张三";state.age=20;},modify_age2(state,payload){//带参数修改,payload是传入的对象,官网叫载荷(payload)state.name=payload.name;state.age=payload.age;}}
在组件中,我们要使用this.$store.commit('xxx(方法名)', 参数;
参数可以是对象也可以是单一属性
<template><div>我放在store中的数据是{{this.$store.state.name}},{{this.$store.state.age}}<button@click="setDefault">不带参修改</button><button@click="setparameter">带参修改</button></div></template><script>exportdefault{methods:{setDefault(){this.$store.commit("modify_age");},setparameter(){this.$store.commit("modify_age2",{name:"王五",age:100});//载荷形式,传入可以使对象或者单个属性//this.$store.commit({//对象形式,传入可以使对象或者单个属性//type:"modify_age2",//name:"王五",//age:100,//});});},},};</script>
anction--同步/异步更改状态
Action 类似于 mutation,不同在于:
Action 提交的是 mutation,而不是直接变更状态。
Action 可以包含任意异步操作。
后台API请求在这个模块进行请求。所有的操作最后都要到达mutation进行操作,更改state的状态。
还是上面一个例子,异步修改state的属性
先上代码
constactions={asy_modify(context){//无参setTimeout(()=>{//异步操作context.commit("modify_age")},2000);},asy_modify2(context,plyload){//有参setTimeout(()=>{context.commit("modify_age2",plyload);},2000);}}constmutations={modify_age(state){//不带参数修改age属性,state是默认的参数state.name="张三";state.age=20;},modify_age2(state,payload){//带参数修改,payload是传入的对象,官网叫载荷(payload)state.name=payload.name;state.age=payload.age;}}conststate={name:'浪漫主义码农',age:18,}
在组件中使用this.$store.dispatch('xxx')
<template><div>我放在store中的数据是{{this.$store.state.name}},{{this.$store.state.age}}<button@click="setDefault">不带参修改</button><button@click="setparameter">带参修改</button></div></template><script>exportdefault{methods:{setDefault(){this.$store.dispatch("asy_modify");},setparameter(){this.$store.dispatch("asy_modify2",{name:"王五",age:100});//载荷形式,传入可以使对象或者单个属性//this.$store.dispatch({//对象形式,传入可以使对象或者单个属性//type:"asy_modify2",//name:"王五",//age:100,//});},},};</script>
注意观察时间,2s后变化。
分析一波:
Action 里面的函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit
提交一个 mutation,或者通过 context.state
和 context.getters
来获取 state 和 getters。
action事件的触发同样可以使用载荷和对象两种方式
6. getter
getter,我们可以理解为是对store中state的一些派生状态,也可以理解为一种计算属性,它类似于计算属性一样,返回值会根据它的依赖被缓存起来,且依赖对象发生改变的时候它才会被重新计算。
getter属性相当于很多个组件需要对数据进行一样的处理,可以理解为公共的计算属性。
这样就很清晰了
Getter 接受 state 作为其第一个参数,也可以使用箭头函数。
constgetters={get_object:function(state){//无参if(state.age<18){returnstate.name+'未成年'}returnstate.name+'已经成年了'},get_object2:function(state){//有参数returnfunction(value){returnstate.name+value;}}}
组件中{this.$store.getters.xxx
来获取
<template><div>我放在store中的数据是{{this.$store.state.name}},{{this.$store.state.age}}<br/><span>不带参数的数据:{{this.$store.getters.get_object}}</span><br/><span>带参数的数据(携带一个刚好18岁):{{this.$store.getters.get_object2("刚好18岁")}}</span></div></template>
7.Modoules
Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块。这里就不过多介绍了,看官方文档(Module | Vuex (vuejs.org))
8.辅助函数
vuex提供了几个的辅助函数,有mapState、mapGetter、mapMutation、mapAction。都是一些复杂语句的简写形式。
引入函数
importstorefrom'./store/index'//引入写好的store.....newVue({el:'#app',router,store,//使用storetemplate:'',components:{App}})0
mapState
如果state中的数据很多,那我们要重复写很多这样的this.$store.state.XXX
代码,我们就可以通过mapState来映射。
数组的写法
importstorefrom'./store/index'//引入写好的store.....newVue({el:'#app',router,store,//使用storetemplate:'',components:{App}})1
如果你想取名别名的话,就要写成对象的形式
importstorefrom'./store/index'//引入写好的store.....newVue({el:'#app',router,store,//使用storetemplate:'',components:{App}})2
mapGetters
mapGetters和mapState很相似,只不过是映射Getters。替代this.$store.getters.XXX
importstorefrom'./store/index'//引入写好的store.....newVue({el:'#app',router,store,//使用storetemplate:'',components:{App}})3
mapMutation
替代this.$store.commit('XXX')
importstorefrom'./store/index'//引入写好的store.....newVue({el:'#app',router,store,//使用storetemplate:'',components:{App}})4
mapAction
替代this.$store.dispatch('XXX')
importstorefrom'./store/index'//引入写好的store.....newVue({el:'#app',router,store,//使用storetemplate:'',components:{App}})5
以上这些辅助函数,涉及到传参都需在使用的计算属性的时候传入。
四、写在最后
更具体的请看官网文档,欢迎各位大佬指点江山。
看到最后点赞收藏吧,听说评论区可以抽奖噢!