跳至主要內容

vuex

技术中心大约 3 分钟

vuex

在前面我们讲了组件间的通信,最主要的都是子传父,父传子。

vuex可以把所有的数据都存在一个公用的容器里面,所有组件都可以使用这个容器中的数据。

vuex也叫状态管理模式,数据也叫做状态

  • state:存储store的各种状态
  • mutation: 通过更改状态,改变store的状态只能通过mutation方法
  • action: 异步更改状态
  • module: 模块化
  • getter: 相当于计算属性,计算出一些新的状态值
vuex
vuex
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex) // 默认会执行当前插件的install方法

// 通过Vue中的一个属性Store创建一个store的实例
// 在vue的初始化过程中, 注入了一个store属性,内部会将这个属性放到每个组件的$store上
export default new Vuex.Store({
  state: { // 单一数据源
    age: 10
  },
  getters: { // 类似于计算属性
    myAge(state) { // 使用状态计算出一个新的状态
      return state.age + 20
    }
  },
  mutations: { // 同步更改状态
    changeAge(state, age) { // 修改状态的方法,同步的修改
      state.age = age
    }
  },
  actions: {
    changeAgeAsync({commit}, age) {
      setTimeout(() => {
        commit('changeAge', age)
      }, 1000)
    }
  },
  modules: {
  }
})
<template>
  <div id="app">
    {{$store.state.age}}
    <button @click="changeState">更改数据</button>
    <button @click="changeStateAsync">异步更改</button>


    <div>我的年龄:{{$store.getters.myAge}}</div>

    <hello></hello>
  </div>
</template>
<script>
  import Hello from './components/hello.vue'
  export default {
    components: {
      Hello
    },
    methods: {
      changeState() {
        this.$store.commit('changeAge', 100)
      },
      changeStateAsync() {
        this.$store.dispatch('changeAgeAsync', 50)
      }
    },
  }
</script>
<style lang="less">
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

#nav {
  padding: 30px;

  a {
    font-weight: bold;
    color: #2c3e50;

    &.router-link-exact-active {
      color: #42b983;
    }
  }
}
</style>

vuex辅助函数

  • mapState

    state的辅助函数需要映射到计算属性中computed,映射的名称一定要相同,然后就可以通过this访问到state。

    export default {
      name: 'Hello',
      computed: {
        ...mapState(['age'])
      }
    }
    <div>
        通过辅助函数:
        <div>{{age}}</div>
      </div>
    
  • mapMutations

    mutation的辅助函数mapMutations把mutations里面的方法映射到methods中。映射的名称一定要相同,然后就可以通过this调用mutaition的方法。

    <button @click="changeAgeMapMutation">
      通过辅助函数mapMutations更改数据
    </button>
    methods: {
        ...mapMutations(['changeAge']),
        changeAgeMapMutation() {
          this.changeAge(300)
        }
      }
    
  • mapActions

    mapAcions:把actions里面的方法映射到methods中

      <button @click="changeAgemapActions">
        通过辅助函数mapActions异步更改数据
      </button>
    
      methods: {
        ...mapActions(['changeAgeAsync']),
        changeAgemapActions() {
          this.changeAgeAsync(700)
        }
      }
    
    
  • mapGetters

mapGetters:把getters属性映射到computed身上

module

Vuex 允许我们将 store 分割成大大小小的对象,每个对象也都拥有自己的 state、getter、mutation、action,这个对象我们把它叫做 module(模块),在模块中还可以继续嵌套子模块、子子模块 ……

命名空间

如果模块不使用命名空间的话,默认情况下模块内部的 getter, action 和 mutation是注册在全局全局命名空间的

想要让模块内部的 getter, mutation , action只作用域当前局部模块内的话可以给模块添加namespaced属性:

export default {
  namespaced:true,
  stateB: { // 单一数据源
    ageB: 10
  },
  getters: { // 类似于计算属性
    myAge(state) { // 使用状态计算出一个新的状态
      return state.ageB + 20
    }
  },
  mutations: { // 同步更改状态
    changeAge(state, age) { // 修改状态的方法,同步的修改
      console.log('moduleB---changeAge')
      state.ageB = age
    }
  },
  actions: {
    changeAgeAsync({commit}, age) {
      console.log('moduleB---changeAgeAsync')
      setTimeout(() => {
        commit('changeAge', age)
      }, 1000)
    }
  },
  modules: {
  }
}

当开启命名空间的模块被注册后它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名,所以触发路径也有所改变:

...mapState({
    moduleAage: state => state.moduleA.ageA
  }),
  ...mapMutations({
    changeAge: 'moduleA/changeAge',
    changeAgeB: 'moduleB/changeAge'
  }),
  changeAgeMapMutation() {
    this.changeAge(300)
    // this.$store.commit('moduleA/changeAge', 500)
  },