Vuex它是专门为Vue.js应用程序设计的状态管理工具。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。通俗来讲当有很多组件,组件与组件之间需要进行相互通信,这时就可以用到Vuex保存多个组件的共享状态,这时只需求state就可以在组件之间同步状态了。

  vuex的特点是把数据单独的隔离形成一棵树状图,单独隔离这就说明它有自己的生态系统,其中action作为数据输入,state作为数据输出。只能在mutations里修改state,actions不能直接修改state。在mutations中修改state的数据,它只能是同步操作,不能存在异步的操作(但如果是异步也不会报错,只是不建议)。如果是异步的操作,那可以把操作放在action中,拿到数据再通过mutations同步进行处理。下面我们来详细分析vuex的用法及核心概念。

  一、基本使用

  1、安装 npm install vuex --save

  2、在src目录下新建一个vuex的目录store并进行资源的引入,通过Vue.use()安装

import Vue from 'Vue'
import Vuex from 'vuex'

Vue.use(Vuex)

  3、安装vuex后,创建一个store.

export default new Vuex.Store({
   state:{count:100}
})

  4、为了在vue组件中访问,vuex提供了一个从根组件向所有子组件,以store选项的方式“注入”store

new Vue({
    el:'#app',
    store:store,
})    

  每一个vuex应用的核心就是store(仓库)。store它就是一个容器,包含着应用中大部分的state(状态)。vuex的状态存储是响应式的,当vue组件从store中读取state,state发生变化 ,那相应的组件也会变化更新。不能直接的改变仓库中的state,改变的唯一方法就是显示的提交mutation.这样可以方便跟踪每一个状态的变化。来面来分别介绍这些概念。

  二、核心概念

  1、state

  vuex使用单一状态树,用一个对象包含全部的应用层级状态。state它是这一状态管理工具唯一的数据源,所有的数据都存储在这里面。这说明了,每个应用将仅仅包含一个store实例。那如何在vue组件中展示呢?由于vuex是响应式的,最简单的方法是在计算属性中返回某个状态。 

创建一个名show的组件
<template>
   <div>
       <h1>{{this.$store.state.count}}</h1>
   </div>
</template>
<script>
export default{
   name: 'show',
   computed:{
       count(){
           return this.$store.state.count
       }
   }
}
</script>
<style lang='less'></style>

  当this.$store.state.count发生变化时,都会重新计算属性,触发更新相关联的DOM.

  如果一个组件需求获取的状态有多个时,如果把这些状态都声明为计算属性,那会很冗余,所以我们可以用发mapState辅助函数来帮助计算属性,mapstate其实就是把state中的属性映射到computed中。在使用它之前先在进行引入。如下所示:

index.js
export default new Vuex.Store({
   state: {
    //这里放置的是公用数据
    count:100,
    from:'china'
    
  } 
})
-------------------------------------------
show.vue
<template>
  <div>
        <h1>{{count}}</h1>
        <h3>{{sex}}</h3>
        <h3>{{from}}</h3>
  </div>
</template>
<script>
import { mapState } from "vuex";
export default {
  name: "show",
  data() {
    return {
      str: "国籍"
    };
  },
  computed: mapState({
    //第一种写法
    count: "count", //当名字一样时
    //第二名写法,使用箭头函数
    sex: state => state.from,
    //第三种写法,使用普通函数(this指向实例)
    from: function(state) {
      return this.str + ":" + state.from;
    }
  })
};
</script>
<style lang='less'></style>

  当然computed不会因为引入了mapState辅助函数而失去原有的功能,但mapstate函数返回的是一个对象,这两者要如何混合使用呢?这时,需求使用一个工具函数将多个对象合并为一个,将最终对象传给computed属性。如下所示:

computed: {
  localComputed () { 
     //......  
 },
     // 使用对象展开运算符将此对象混入到外部对象中
       ...mapState({
      // ......
  })
}

  2、getter

  有时候需求从store中的state中派生出一些状态,所以要用到getter,getter是store的计算属性,getter返回的值会会根据依赖被缓存起来,只有当它的依赖值发生改变才会被重新计算。它的使用方法是 $store.getters.属性名。它可带参数,也可以不带参数,接受state为其第一个参数,也可以接受其它getter作为第二个参数。

//index.js
export default new Vuex.Store({
  state: {
    list: [1, 2, 3, 5, 6, 7, 8, 9, 0]
  },
  getters: {
    fillteredList: (state, getters)=>{
      console.log(state,getters);
      return state.list.filter(item => item > 5)
    }
  }
})
--------------------------------
//show.vue
<template>
  <div></div>
</template>
<script>
// import { mapState } from "vuex";
export default {
  name: "show",
  computed:{
      list(){
          return this.$store.getters.filteredList;
      }
  }
};
</script>
<style lang='less'>
</style>

  我们可以通过mapGetters辅助函数将store中的getter映射到局部计算属性,使用前还是要进行引入。

import { mapGetters } from 'vuex'
export default {
  // ...
  computed: {
  // 使用对象展开运算符将 getter 混入 computed 对象中
    ...mapGetters([
    //如果想将一个getter属性另取一个名字,使用对象形式
     doneCout:'donetodoCount'
      // ...
    ])
  }
}
    

  3、mutation

  我们知道更改vuex中store状态的唯一方法就是提交mutation.vuex中的mutation类似于事件,每个mutation都有一个字符串的事件类型(type)和一个回调函数(handler),这个回调函数就是实际进行状态更改的地方,可以看成是{type:handler()},调用type时用到store.commit方法。

//index.js
export default new Vuex.Store({
  state: {
    //这里放公用的数据
    count: 100,
    age: 20
  },
  mutations: {
    //这里面的函数都是用来修改state中状态的
    //用this.$store.commit()方法触发
    changeCount(state, option) {
      //state是我们公用状态,option是执行这个函数时传递的值,最多只有两个参数,最少为一个
      console.log(state, option);
      console.log(arguments);
      // state.count += option;
      state.count += option.num;

    }
  }
})
-----------------------------------------------
button.vue
<template>
  <div>
    <button @click="add">增加</button>
    <button @click="minus">减少</button>
    <h2>{{res}}</h2>
  </div>
</template>
<script>
export default {
  name: "xxx",
  computed:{
      res(){
          return this.$store.state.count;
      }
  },
//在methods中提交 methods: { add() {
//commit()执行会默认去mutations中查找对应的函数并执行 // this.$store.commit("changeCount",10); //还可以改变风格 this.$store.commit({type:'changeCount',num:100}) }, minus() { // this.$store.commit("changeCount", -10); this.$store.commit({type:'changeCount',num:-100}) } } }; </script> <style lang='less'></style>

  需求注意的是mutation必须是同步的,这是为了调试方便。在项目中使用时,一般将常量放在单独的文件中,这样更有助于协作开发,提高效率。

//mutation-type.js
export const some_mutation = 'some_mutation'
//store.js
import Vuex from 'vuex'
import { some_mutation } from './mutation-type'

let store = new Vuex.Store({
  state: {......},
  mutations: {
    [some_mutation](state, option) {
      //......
    }
  }
})

 可以使用mapMutations辅助函数。它的作用是把mutations中的方法映射到组件的methods中。使用辅助函数之前还是要先引入,如下所示:

<template>
  <div>
    <button @click="add(30)">增加</button>
    <button @click="minus">减少</button>
    <button @click="changeCount(50)">test</button>
    <h2>{{res}}</h2>
  </div>
</template>
<script>
import {mapMutations} from 'vuex'
export default {
  name: "xxx",
  computed:{
      res(){
          return this.$store.state.count;
      }
  },
  methods: {
      ...mapMutations(['changeCount']),
      ...mapMutations({add:'changeCount'}),
    // add() {
    //  this.$store.commit('changeCount',100);
    // },
    minus() {
      this.$store.commit("changeCount", -10);
    }
  }
};
</script>
<style lang='less'></style>

  4、action

  actions是为异步操作而设置的。因为mutations只能是同步操作,但在实际的项目中会存在异步操作,这样就变成了在action中去提交mutation,然后在组件的methods中去提交action。只在在提交的时候使用的是dispatch函数,而mutations使用的是commit函数.

actions:{
    //这里面的函数最终都会触发mutations中的函数
    //这些函数中原则上不能直接修改state中的数据
    //通过this.$store.dispatch()
    changeCount(store, option){
      //console.log(store, option);
      setTimeout(() => {
        store.commit('changeCount',option)
      }, 200);
      // console.log(arguments)
    }
  }
--------------------------------------
  methods: {
    add() {
    this.$store.dispatch('changeCount',100,200);
    },
    minus() {
    this.$store.dispatch('changeCount',-100);

    }
  }

  5、module

  由于vuex使用了单一状态树,应用的所有状态都会集中到一个比较大的对象中,当应用比较复杂的时候,store对象就会变的十分的臃肿。所以才有了module,它可以将store分割成模块,每个模块有自己的state,getter,mutation,action甚至是嵌套的子模块,从上到下进行同样方式的分割。它主要是进行模块的划分。

const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态

  对于模块内部的mutation和getter来说,接受的第一个参数是模块的局部状态state。根结点的状态为rootState。

  总结一下,对于含有vuex的项目来说,其结构大体如下:1、应用层级的状态都应该集中在store2、提交mutation是更改state的唯一方式 3、异步操作应试放在action里。如果store文件过大,可以将action,mutation,getter进行分割,分割到单独的文件中。

 

  

  

  

 

posted on 2020-07-31 08:30  人称小小贩  阅读(662)  评论(0编辑  收藏  举报