官网传送门
概述
何为 Vuex ?
Vuex 专门在 Vue 中实现集中式状态(数据)管理的一个 Vue 插件,对 Vue 应用中多个组件的共享状态进行集中式的管理,也是一种组件间通信的方式,适用于任意组件间通信
何时用 Vuex ?
- 多个组件依赖于同一状态
- 来自不同组件的行为需要变更同一状态
Vuex 工作原理图:
官方 Vuex 项目结构示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| . ├── index.html ├── main.js ├── api │ └── ... # 抽取出API请求 ├── components │ ├── App.vue │ └── ... └── store ├── index.js # 组装模块并导出 store 的地方 ├── actions.js # 根级别的 action ├── mutations.js # 根级别的 mutation └── modules ├── cart.js # 购物车模块 └── products.js # 产品模块
|
Vuex 核心概念
state
actions
- 值为一个对象,包含多个响应用户动作的回调函数
- 通过
commit()
触发 mutation 中函数的调用,间接更新 state
- 可包含异步代码
mutations
- 值为一个对象,包含多个直接更新 state 的方法
- 不能写异步代码,只能单纯地操作 state
getters
- 值为一个对象,包含多个用于返回数据的函数
- 类似于计算属性,getters 返回的数据依赖于 state 的数据
modules
- 一个 module 是一个 store 的配置对象,与一个组件对应
搭建 Vuex 环境
安装 Vuex:npm install vuex@3 --save
:::warning
注意:Vue2 安装 Vuex3,Vue3 安装 Vuex4,版本需对应。
:::
创建文件 src/store/index.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13
| import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex)
const actions = {} const mutations = {} const state = {}
export default new Vuex.Store({ actions, mutations, state, })
|
main.js
配置 store
:
1 2 3 4 5 6 7
| import store from './store'
new Vue({ el: '#app', store, render: (h) => h(App), })
|
基本使用
组件实例与 Actions
和 Mutations
对话:
- 若没有网络请求或其他业务逻辑,组件中也可以越过
actions
,即不写dispatch
,直接编写commit
:
1 2 3 4 5 6 7 8 9 10 11
| methods: { increment() { this.$store.commit('ADD', this.number) }, incrementOdd() { this.$store.dispatch('addOdd', this.number) }, incrementAsync() { this.$store.dispatch('addAsync', this.number) } }
|
定义 Actions
和 Mutations
:
context
是一个迷你版的 store
,可访问 dispatch
, commit
方法和 state
mutations
的动作类型一般用大写,与 actions
区分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex)
const actions = { addOdd(context, value) { if (context.state.sum % 2 !== 0) { context.commit('ADD', value) } }, addAsync(context, value) { setTimeout(() => { context.commit('ADD', value) }) }, } const mutations = { ADD(state, value) { state.sum += value }, }
const state = { sum: 0, }
export default new Vuex.Store({ actions, mutations, state, })
|
组件访问 Vuex 的数据:
1
| <p>{{ $store.state.sum }}</p>
|
getters 的使用
- 当
state
中的数据需要经过加工后再使用时,可以使用 getters
加工
- 它不是必须的,当加工逻辑复杂且需要复用时,可以考虑使用
state
与 getters
的关系有点像 data
和 computed
的关系
- 组件读取:
$store.getters.bigSum
1 2 3 4 5 6 7 8 9 10 11 12 13
| ... const getters = { bigSum(state) { return state.sum * 10 } }
export default new Vuex.Store({ actions, mutations, state, getters })
|
四个 mapXxx 方法
mapState()
- 将
state
状态映射为计算属性
- 对象写法:键为自取的计算属性名,值为对应的状态(必须为字符串)
- 数组写法:当键值同名,可直接写状态名(字符串)
- 函数返回一个对象:
{sum: f, price: f}
- 注意对象的
...{}
展开写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import { mapState } from 'vuex'
computed: { sum() { return this.$store.state.sum }, price() { return this.$store.state.price },
...mapState({sum: 'sum', price: 'price'}),
...mapState(['sum', 'price']) }
|
mapGetters
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import { mapGetters } from 'vuex'
computed: { bigSum() { return this.$store.getters.bigSum }, double() { return this.$store.getters.double },
...mapGetters({bigSum: 'bigSum', double: 'double'}),
...mapGetters(['bigSum', 'double']), }
|
mapActions
- 生成与
actions
对话的函数,即包含 $store.dispatch()
mapActions
生成的函数不会传入参数,需要在调用时手动传入数据,不传参默认传入 $event
- 数组写法要注意函数名和
actions
动作类型同名,调用时勿写错
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import { mapActions } from 'vuex'
methods: { incrementOdd() { this.$store.dispatch('addOdd', this.number) }, incrementAsync() { this.$store.dispatch('addAsync', this.number) },
...mapActions({incrementOdd: 'addOdd', incrementAsync: 'addAsync'}),
...mapActions(['addOdd', 'addAsync']), }
|
1
| <button @click="incrementOdd(number)">奇数+1</button>
|
mapMutations
- 生成与
mutations
对话的函数,即包含 $store.commit()
- 同样注意传递参数,以及数组形式函数名的问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import { mapMutations } from 'vuex'
methods: { increment() { this.$store.commit('ADD', this.number) }, decrement() { this.$store.commit('SUB', this.number) },
...mapMutations({increment: 'ADD', decrement: 'SUB'}),
...mapMutations(['ADD', 'SUB']), }
|
Vuex 模块化&命名空间
让代码更好维护,让多种数据分类更加明确,每一类数据及其相关操作对应一个 store
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| const countAbout = { namespaced: true, state: { sum: 0 }, actions: {...}, mutations: {...}, getters: { bigSum(state) { return state.sum * 10 } } } const personAbout = { namespaced: true, state: { personList: [] }, actions: {...}, mutations: {...}, getters: {...} }
export default new Vuex.Store({ modules: { countAbout, personAbout } })
|
开启命名空间后,组件中读取 state
数据:
1 2 3 4 5
| this.$store.state.personAbout.personList
...mapState('countAbout',['sum','school']),
|
开启命名空间后,组件中读取 getters
数据:
1 2 3 4 5
| this.$store.getters['countAbout/bigSum']
...mapGetters('countAbout',['bigSum'])
|
开启命名空间后,组件中调用 dispatch
1 2 3 4
| this.$store.dispatch('countAbout/addODdd', this.number)
...mapActions('countAbout', {incrementOdd:'addOdd', incrementWait:'addAsync'})
|
开启命名空间后,组件中调用 commit
1 2 3 4
| this.$store.commit('personAbout/ADD_PERSON', person)
...mapMutations('countAbout',{increment:'ADD',decrement:'SUB'}),
|