最近对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 谢谢~

建议来来回回读三遍

posted on 2017-10-27 12:25  维尼-winnie  阅读(575)  评论(0编辑  收藏  举报