最近对vue中的状态管理进行了学习,以下内容为个人的总结。
状态管理这个东西,我觉得可以用闭包的角度去理解它-防止污染。
状态管理的初衷很简单,就是把多个组件共用的一个变量给提取出来,防止被无意更改(污染)。于是就有了vuex这个东西。使用它我们需要自己先去安装
命令: npm install vuex --save
然后它就会自动的出现在我们配置文件的依赖中了。
我们在使用之前,要先告诉vue我们要使用它啦,于是要Vue.use(vuex).
然后我们可以创建一个store.js文件,我们所有相关的操作,将会在里面完成。
我们要生成一个状态管理对象,把相关的东西都丢进去。如下
const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } } })
上面对象中的state,就是我们提取出来的公共状态了。你会看到有个叫做mutation的属性,它是一个对象。我们对state里面变量的更改将全部通过这个方法去完成(这也是官方所推荐的)。但是有人会说了,你这个东西不是平时用的方法啊(methods),而且在这个store.js文件里面,根本拿不到。
所以,我们会把这个js文件暴露出去,在我们的main.js文件里面导入,然后在注入到我们的实例对象里面。
这样,是不是已经算是解决了拿不到的这个问题啦。至于另外一个触发方法的问题,我们接着往下讲。
我们官网中推荐的方式是 methods>action>mutation>state
也就是通过事件去触发相关的方法(methods),然后方法中会通过this.$store.dispatch("action中相应的方法名")这种条语句去触发相应的action方法,action中相应的方法会通过commit("mutation中对应的方法名")这种方式去触发相应的方法。最终达到了改变state.目标属性 的目的。
----------------分割线---------------
总的来说就是这么一个过程。接下来我会讲述下实现过程中vuex中的一些简化函数。
注意:通过这种在实例中注入的方式,我们的子组件就能访问store对象啦,一般直接通过this.$store就是我们的store对象。
--------------------------------------
首先我们要理解一点,就是这些个变量或者属性只是被保护起来了,并不是不用,不然这个东西还有什么意义呢。
。。。。。。。。。。,,,,,,,
所以接下来我们从最初始的state开始说起。
一般我们的子组件会有想要访问到我们state中相关属性值的需求,我们可以这么做
..... computed:{ pro(){ //假设我们要访问的state属性和我们的计 算属性名一样 return this.$store.state.pro } }
上面这么做很简单,也很容易让人明白,但是问题来了,如果有十个计算属性也要引用state中的属性,一直重复写this.$store.state.XXX会不会很麻烦,而且显得代码看起来非常冗余。所以为了避免这种情况发生,我们的vuex帮我们创建了一个mapState函数,它直接把state映射到我们的组件当中了。具体看下边
import {mapState} from "vuex"; // export default { // 下面这两种写法都可以 computed: mapState({ count: state => state.count // 组件内的每一个属性函数都会获得一个默 认参数state //然后通过state 直接获取它的目标属性,这样写更简洁 count: 'count' // 'count' 直接映射到state 对象中的count, 它相当于 this.$store.state.count, }) }
如果我们组件中的属性和state 中的属性名称一样,我们不想改名字,那就把直接把属性名写在数组中。
import {mapState} from "vuex"; export default { computed: mapState([ // 数组 "count" ]) }
不过这种方式说实话我不太喜欢,感觉有点简洁过头了。
可能会有这么一个场景,你的计算属性对象中可能有其他的属性要用到你在mapState函数中的属性,那么我们就需要有个类似于把mapState函数中的属性分离出来(供其它属性能够访问到)的操作,我们可以像用扩展运算符,就像下边
import {mapState} from "vuex"; export default { computed: { localComputed () { return this.count + 10; }, ...mapState({ count: "count" }) } }
这样我们的localComputed属性能访问到我们mapState函数中相关的计算属性了。
这就是我们的mapState函数的作用了
-----------------分割线---------------
我们前面讲到过,要改变state里面的属性值,要使用我们的mutation中的方法,像下面
const store = new Vuex.Store({ state: { count:0 }, mutations: { increment(state) { state.count++; }, decrement(state) { state.count-- } } })
这里需要注意一下,官网推荐我们把mutation中的方法使用大写。
上面我们就完成了对mutation的书写。
我们前面说过,要触发mutation中的方法,需要使用commit方法去实现。
注意:在我们的mutation中,方法名叫类型,每个mutation中的类型(type)就是对应的方法名。从上面我们可以看到,我们可以直接把mutation选项写在我们的store对象里面。
------------------------
我们可以通过使用methods中的方法去触发我们的mutation中的对应函数,但是这显然和我最初说的流程行为不一致。我们需要在store中的actions选项去触发相应的函数。
具体实现看下面
store = new Vuex.Store({ state: { count:0 }, mutations: { INCREMENT(state) { state.count++; }, DECREMENT(state) { state.count-- } }, actions: { increment(context) { context.commit("INCREMENT"); }, decrement(context) { context.commit("DECREMENT"); } } })
我们可以看到,我们actions中的方法有一个默认的context参数,它其实指代的就是我们的store实例对象,所以可以看到方法体里面其实是用了实例对象的commit方法去触发对应的函数,所以我们其实可以使用es6中的解构赋值的操作。就像下面
actions: { increment({commit}){ commit("INCREMENT") }, decrement({commit}){ commit("DECREMENT") } }
好了,既然已经讲到action了,其实就差最后的凌门一脚了。请看下面网上的引用例子
<template> <div> <button @click="increment">+1</button> <button @click="decrement">-1</button> </div> </template> <script> export default { methods: { increment(){ this.$store.dispatch("increment"); }, decrement() { this.$store.dispatch("decrement") } } } </script>
我们看到把对应的"参数"放到methods里面对应的dispatch方法,这个参数其实就是我们的action名。我们可以利用这样的方式分发执行我们对应的方法啦。这么一看,有木有一种一目了然的感觉。
其实像上面这么写,看着还是有点麻烦,因为this.$store.dispatch这句多少有点长,所以我们的vuex又给我们来了个"简化函数mapAction",看下面
import {mapActions} from "vuex"; export default { methods: { ...mapActions(["increment"...]) } }
像这种组件中的事件处理函数名字和 action的名字是相同的,直接把 事件处理函数名字放到一个数组中.
切记,只有我们的事件处理函数名和dispatch中的action名一样时才可以这么写。
它和mapState 是一样的,把我们的action 直接映射到store 里面的action中。
如果事件处理函数名字和action的名字不同,给mapActions 提供一个对象,对象的属性是事件处理函数名字, 属性值是 对应的dispatch 的action 的名字。
import {mapActions} from "vuex"; export default { methods: { ...mapActions(["decrement"]), // mapActions 对应做出改变 ...mapActions({ add: "increment" }) } }
这里补充一点,我们的mutation函数除了可以接受默认的值以外,还可以接受传参
commit(方法名,值),根据这点,我们可以得出,我们mutation中的方法可以有一个value参数用于接受传过来的值。+dispatch(方法名,value)。
----------------哦弥陀佛------------
有的组件中获取到 store 中的state, 需要对进行加工才能使用,computed 属性中就需要写操作函数,如果有多个组件中都需要进行这个操作,那么在各个组件中都写相同的函数,那就非常麻烦,这时可以把这个相同的操作写到store 中的getters, 每个组件只要引用getter 就可以了,非常方便。Getter 就是把组件中共有的对state 的操作进行了提取,它就相当于 对state 的computed. 所以它会获得state 作为第一个参数。
我们在store对象中写getters属性对象,如下示例
getters: { // getters countAnother: function (state) { return state.anotherIncrement } }
我们在computed属性中就可以直接通过
this.$store.getters.countAnother去获取了。
vuex 也提供了mapGetters 方法,和其的mapState,mapActions 是一样的,如果组件中使用的getters 和store 里面的getters 相同,那就用 数组形式,如果不相同,那就要用对象形式。
computed: { show: function() { return this.$store.state.waiting; }, ...mapGetters{["countAnother"]} },
--------结束 如果代码侵权,发我邮箱 15158614067@163.com 谢谢~
建议来来回回读三遍