Skip to content

Vuex 状态管理

一种组件间通信的方式, 适用于任意组件间通信

概述

专门在Vue中实现集中式状态、数据管理的一个Vue插件, 对Vue应用中多个组件的共享状态进行集中式的管理: 读、写

源码地址: https://github.com/vuejs/vuex

  • 示例图:

Vuex

Vuex 使用时机

  • 多个组件依赖同一状态
  • 来自不同组件的行为需要变更同一状态

Vuex 工作原理

Vuex分为三部分:

  1. Actions: 用来处理异步回调获取数据的模块, 如调用后端API, 如果没有异步操作可跳过Actions直接调用Mutations中的方法处理数据
  2. Mutations: 用来处理State中数据的模块
  3. State: 用来存储数据的模块, 类型组件中的data属性
  • 示意图

Vuex

环境搭建

第一步: 安装

  • 安装Vuex:
bash
npm i vuex

第二步: 应用Vuex并创建store

  • 需要在Vue.use(Vuex)应用Vuex之后才能创建store实例, 且模块化会将import语句提前, 所有没有在main.js中应用Vuex

  • src目录新建store文件夹, 并在文件夹中新建index.js文件

  • index.js代码示例

js
// 引入 Vue
import Vue from 'vue'
// 引入 Vuex
import Vuex from 'vuex'
// 应用 Vuex
Vue.use(Vuex)
// 创建 actions => 响应组件中的动作
const actions = { ... }
// 创建 mutations => 操作 state 中的数据
const mutations = { ... }
// 创建 state => 存储数据
const state = { ... }
// 创建并导出 store
export default new Vuex.Store({
  actions,
  mutations,
  state
})

第三步: 在main.js中将store挂载到Vue

  • 代码示例
js
import store from './store'
new Vue({
  el: '#app',
  store
})

注意

应用Vuex与创建store实例的顺序问题, 不用在main.js中应用Vuex, 因为importstore会先执行

Vuex 基本使用

组件中读取Vuex中的数据:

  • $store.state.value

组件中修改Vuex中的数据:

  • $store.dispatch('actions中的方法名', 参数数据)
  • $store.commit('mutations中的方法名', 参数数据)

若没有网络请求或其他业务逻辑, 组件中可以越过actions, 直接使用commit调用mutations中的方法

  • 组件中示例代码:
js
export default {
  data: {
    n: 1
  },
  methods: {
    add() {
      this.$store.commit('addNormal', this.n)
    },
    addByWait() {
      this.$store.dispatch('addWait', this.n)
    }
  }
}
  • store中示例代码:
js
// 创建并导出 store
export default new Store({
  actions: {
    // 响应动作调用操作 mutations 中的事件
    addWait() {
      setTimeout(() => {
        context.commit('addNormal', value)
      }, 1000)
    }
  },
  mutations: {
    // 执行事件
    addNormal(state, value) {
      state.sum =+ value
    }
  },
  state: {
    sum: 0
  }
})

Getters

概念: 用来加工state中的数据, 相似于组件中的computed计算属性, 当state中的数据需要加工时使用

  • store中配置getters:
js
export default new Store({
  getters: {
    bigSum(state) {
      return state.sum * 10
    }
  }
})
  • 组件中读取数据
html
<template>
  <h1> 当前求和X10为:{{ $store.getters.bigSum }} </h1>
</template>

Vuex 中 Map 方法的使用

注意

使用以下map方法需要先在组件中引入: import { mapState, mapGetters, mapActions, mapMutations } from 'vuex'

mapState 方法

用于映射state中的数据为计算属性, 共有两种写法:

  1. 对象写法: {key: value}形式, keyvalue一致或不一致时都可使用, 页面中使用key获取数据
  2. 数组写法: ['xxx', 'yyy'], 数组中的元素要与state中的属性名一致, 页面中使用数组中元素获取数据
  • 代码示例:
js
computed: {
  // 对象写法
  ...mapState({getName: 'name', getAge: 'age'})
  // 数组写法
  ...mapState(['name', 'age'])
}

mapGetters 方法

用于映射getters中的数据为计算属性, 共有两种写法:

  1. 对象写法: 与上述mapState方法一致
  2. 数组写法: 与上述mapState方法一致
  • 代码示例:
js
computed: {
  // 对象写法
  ...mapGetters({newName: 'name', newAge: 'age'})
  // 数组写法
  ...mapGetters(['name', 'age'])
}

mapActions 方法

用于生成与actions对话的方法, 即包含$store.dispatch(xxx)的函数, 共有两种写法:

  1. 对象写法: {key: value}形式, keyvalue一致或不一致时都可使用, 其中key用于页面中的绑定事件处理函数
  2. 数组写法: ['xxx', 'yyy'], 数组中的元素要与state中的属性名一致, 数组中元素用于页面中的绑定事件处理函数
  • 代码示例:
js
methods: {
  // 对象写法
  ...mapActions({getName: 'getUserName', getAge: 'getUserAge'})
  // 数组写法
  ...mapActions(['getName', 'getAge'])
}

注意

如需传参要在页面绑定事件时传递参数, 如<button @click="getName(xxx)">获取名字</button>, 否则参数是默认的事件对象$event

mapMutations

用于生成与mutations对话的方法, 即包含$store.commit(xxx)的函数, 共有两种写法:

  1. 对象写法: 与上述mapActions方法一致
  2. 数组写法: 与上述mapActions方法一致

传参: 与上述mapActions方法一致

  • 代码示例:
js
methods: {
  // 对象写法
  ...mapMutations({update: 'handleUpdate', del: 'handleDel'})
  // 数组写法
  ...mapMutations(['update', 'del'])
}

Vuex 模块化

目的: 让代码更好维护, 让多种数据分类更加明确

模块化使用步骤

  1. store文件夹新建modules文件夹
  2. modules文件夹中新建不同模块的.js文件
  3. .js文件中分别配置actionsmutationsstate等并导出模块, 需要开启命名空间: namespaced: true
  4. store/index.js文件中分别引入模块, 并配置到modules对象中
  • 代码示例:
js
// store/modules/count.js 文件
export default {
  namespaced: true,
  actions: {
    addWait(context, value) {
      setTimeout(() => {
        context.commit('ADD', value)
      }, 1000)
    }
  },
  mutations: {
    ADD(state, value) {
      state.sum += value
    }
  },
  state: {
    sum: 0
  },
  getters: {
    bigSum(state) {
      return state.sum * 10
    }
  }
}

// store/index.js 文件
import Vue from 'vue'
import Vuex from 'vuex'

import count from './modules/count.js'

Vue.use(Vuex)

export default new Vuex.Store({
  modules: {
    // count: count
    count
  }
})

使用不同模块中的方法

  • 组件中获取模块countstate的数据
js
computed: {
  // 直接获取
  sum() {
    return this.$store.state.count.sum
  }
  // 使用 mapState 获取
  ...mapState('count', ['sum'])
}
  • 组件中获取模块countgetters的数据
js
computed: {
  // 直接获取
  bigSum() {
    return this.$state.getters('count/bigSum')
  }
  // 使用 mapGetters 获取
  ...mapGetters('count', [' '])
}
  • 组件中调用模块countactions的方法
js
methods: {
  // 直接调用
  handleAddWait() {
    this.$store.dispatch('count/addWait')
  }
  // 使用 mapActions 调用
  ...mapActions('count', { handleAddWait: 'addWait' })
}
  • 组件中调用模块countmutations的方法
js
methods: {
  // 直接调用
  handleAdd() {
    this.$store.commit('count/ADD')
  }
  // 使用 mapMutations 调用
  ...mapMutations('count', { handleAdd: 'ADD' })
}