博主前面在 图解Vue组件通讯【一图胜千言】 介绍过父子组件之间的通信、兄弟组件之间的通信、祖先与后代组件之间的通信,但在实际开发过程中,也会遇到非关系组件之间的通信,这时候就需要使用 vuex 这一独立于组件的状态管理工具了。
本文以项目的视角讲解Vuex的使用,讲解概要如下:
创建Vuex、挂载Vuex
state 公共数据源
mutations 修改数据源
actions 异步操作
getters 计算属性
getters和computed 的组合使用
modules 模块
小结
1. 创建vuex、挂载vuex
1.1 安装vuex
npm i vuex@3.6.2
1.2 项目的src目录下,新建store目录 \ index.js :
import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters' // 全局getters,后文说明
import goods from './modules/goods' // 自定义模块,后文说明
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
getters,
mutations: {
},
actions: {
},
modules: {
goods
}
})
1.3 在入口文件main.js中挂载store
import store from '@/store'
new Vue({
store,
router
....
}).$mount('#app')
2. state 公共数据源
2.1 state称为公共数据源,需要共享的数据统一放在state进行储存(类似data)。
项目中基本使用独立模块、独立作用域的state,例如:
在store目录下 \ 新建modules目录 \ goods.js...
// goods.js
export default {
state: {
name: 'Apple Version Pro'
},
getters: {
},
mutations: {
},
actions: {
},
namespaced: true // 开启命名空间,隔离作用域
}
2.2 组件中获取modules下的state
$store.state.模块名.键名
$store.state.goods.name
3. mutations 修改数据源
3.1 mutations 是修改state数据的唯一节点,并且mutations必须是同步的
3.2 创建mutations时,不携带参数
// goods.js
export default {
state: {
price: 2999
},
getters: {
},
mutations: {
increasePrice (state) {
state.price++
}
},
actions: {
},
namespaced: true // 开启命名空间,隔离作用域
}
3.3 使用modules中的的mutations,不传参
$store.commit('模块名/mutation名')
$store.commit('goods/increasePrice')
3.4 创建mutations时,携带参数
// goods.js
export default {
state: {
price: 2999
},
getters: {
},
mutations: {
// 参数1是state, 参数2是传参
// 只存在1个传参, 多个传参使用数组或对象
increasePriceN (state, num) {
state.price += num
}
},
actions: {
},
namespaced: true // 开启命名空间,隔离作用域
}
3.5 使用modules中的的mutations,传参
$store.commit('模块名/mutation名', 参数)
$store.commit('goods/increasePriceN', 199)
4. actions 异步操作
一般在actions里声明函数,函数中可以包含任何异步操作,最后提交mutations,不允许直接修改state数据源。
// goods.js
export default {
state: {
name: 'Apple Version Pro'
},
getters: {
},
mutations: {
setGoodsName (state, val) {
state.name = val
}
},
actions: {
// 参数1是context, 参数2是传参
// 只存在1个传参, 多个传参使用数组或对象
asyncSetGoodsName (context, val) {
setTimeout(() => {
// context.commit可以访问到当前作用域下全部的mutations方法
context.commit('setGoodsName', val)
}, 3000)
}
},
namespaced: true // 开启命名空间,隔离作用域
}
使用modules中的的actions:
$store.dispatch('模块名/actions名', 参数)
$store.dispatch('goods/asyncSetGoodsName', 'Samsung')
5. getters 计算属性
类似于vue中的computed,进行缓存,对state的数据进行加工处理形成新的数据。
示例:
// goods.js
export default {
state: {
nums: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
},
getters: {
// 参数是state,不支持更多参数
// 必须要有返回值!!!
largeNums (state) {
return state.list.filter(item => item > 5)
}
},
mutations: {
},
actions: {
},
namespaced: true // 开启命名空间,隔离作用域
}
// 此处是[]
$store.getters['模块名/getters名']
$store.getters['goods/largeNums']
6. getters和computed 的组合使用
项目中一般会把 `组件的computed` 和 `Vuex的getters` 组合起来使用。这样当 getters 中的相关状态发生变化时,computed 属性会自动重新计算。这样可以确保您的组件在依赖的状态发生变化时得到更新。
示例:
6.1 在store目录下新建 getters.js
// 使用getters监听state变化,实时同步给组件的computed,无需重新获取state
const getters = {
// name为state的键名
// goods为模块名
name: state => state.goods.name,
price: state => state.goods.price
}
export default getters
6.2 在 store \ index.js 中挂载全局的getters
import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters' // 全局getters
import goods from './modules/goods' // 自定义模块
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
getters, // 挂载 getters
mutations: {
},
actions: {
},
modules: {
goods
}
})
6.3 语法
this.$store.getters.键名
this.$store.getters.name
this.$store.getters.price
6.4 代码片段
// 组件A
<template>
<div>
<h2>{{ goodsName }}</h2>
<h2>{{ goodPrice }}</h2>
<div>
</template>
<script>
export default {
name: 'App',
computed: {
goodsName() {
return this.$store.getters.name
},
goodsPrice() {
return this.$store.getters.price
}
}
}
</script>
// 组件B
<template>
<div><div>
</template>
<script>
export default {
name: 'MyComponent',
created () {
// 使用模块中的mutations方法同步修改state数据源,getters和computed的组合会同步刷新数据
this.$store.commit('goods/increasePriceN', 199)
}
}
</script>
7. modules 模块
使用单一的状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿,所以有了vuex的模块化。
基本用法:
1. store目录下 \ 新建modules目录:创建模块,
例如 goods.js \ person.js,
拆分模块后,每个模块都有自己独立作用域的state、mutations、actions、getters...
2. store目录下 \ index.js 中配置modules
import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
import goods from './modules/goods' // 自定义模块A
import person from './modules/person' // 自定义模块B
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
getters,
mutations: {
},
actions: {
},
modules: {
goods, // 自定义模块A
person // 自定义模块B
}
})
8. 小结
8.1 什么是vuex
状态 (数据) 集中管理工具
8.2 什么样的数据适合放在vuex中?
多组件共享的数据
8.3 属性
state: 公共数据源
mutations: 修改公共数据源的唯一节点
actions: 涉及到异步操作放到actions中,包含任何异步操作,提交的是mutations,不能直接修改数据
getters: 基于state派生出的新数据写在这里
8.4 Tips
由于单一状态树,所有的共享数据都放在一个state中,导致state冗余,后期维护性较差,建议拆分模块。modules每个模块都有自己的state,mutations,actions,getters,为了防止协同开发出现的命名冲突问题,一般会为各个模块开启命名空间 namespaced: true
End-----------------------