Vuex插件
vuex 概述
vuex 是实现数据集中式状态管理的插件(plugin)。
vuex可以统一管理数据,其他组件可以使用vuex管理的数据,vuex中数据是唯一的,只要有一个组件更改,那么别的组件对这些数据的引用也会更改。
- 相当于一个数据的托管池。
全局事件总线和 vuex 插件的区别:
全局事件总线关注点:组件和组件之间数据如何传递,一个绑定
$on,一个触发$emit。- 数据实际上还是在局部的组件当中,并没有真正的让数据共享。只是数据传来传去。

image-20230707212811043 vuex 插件的关注点:共享数据本身就在 vuex 上。其中任何一个组件去操作这个数据,其它组件都会同步更新。是真正意义的数据共享。

image-20230707212816475
vuex解决了多个组件间数据同步更新的问题。当多个组件之间依赖于同一状态、来自不同组件的行为需要变更同一状态时,就可以使用vuex。
vuex 环境准备
安装 vuex
# vue2 安装 vuex3 版本 npm i vuex@3 # vue3 安装 vuex4 版本 npm i vuex@4创建 vuex 目录 和 vuex/store.js 文件(规范,非必须)
在 store.js 文件中创建核心 store 对象,并暴露
// 引入Vue,因为下面使用Vuex插件的时候需要Vue
import Vue from 'vue'
// 引入vuex插件
import Vuex from 'vuex'
// 使用插件
Vue.use(Vuex)
// 创建三个vuex插件的核心对象:actions对象、mutations对象、state对象
const actions = {}
const mutations = {}
const state = {}
// 创建store对象(这个store对象是vuex插件中的老大,最核心的对象,这个对象store是用来管理actions对象、mutations对象、state对象。)
const store = new Vuex.Store({
// 它是一个负责执行某个行为的对象
actions : actions,
// 它是一个负责更新的对象
mutations : mutations,
// 它是一个状态对象
state : state
})
// 导出store对象(暴露之后,别人想用可以使用import进行引入)
export default store
// 简写形式
export default new Vuex.Store({actions,mutations,state})在 main.js 中引入store并注册
// 引入Vuex插件中的核心对象store import store from './vuex/store' new Vue({ el : '#app', // 一个全新的配置项,以前没有学过:store // 加上这个配置项之后,vm以及所有的vc对象上都会多一个属性:$store // 以后通过vm.$store或者vc.$store来获取store对象。 // store : store, store, // ES6 简写 render : h => h(App), })通过
.$store来获取绑定的 store 对象。
vuex 核心对象
actions
actions 中的每一个 action 都是一个callback(回调函数),在action这种回调函数中编写复杂的业务逻辑。
const actions = {
// N多个action
// action 可以接收两个参数:
// context:context是vuex的上下文(context可以看做是store对象的缩小版)
// value:传过来的数据
//plusOne : function(){}
// 简写
plusOne(context, value){
// 处理业务
value = value + 1
// 调用其它的action这个回调函数
// context.dispatch('otherAction', value)
// ... 直至业务逻辑完成
// 业务逻辑处理完成之后,继续向下一个环节走,就轮到了数据的*更新*。
// 即:提交上下文环境
// context.commit('mutation', value)
context.commit('PLUS_ONE', value)
},
// 这里可能还会有其它的action
// ...
/* otherAction(context, value){
console.log(6666)
} */
}mutations
mutations 中的每一个 mutation 也都是一个callback(回调函数),每个 mutation 都用来更新 state。state 是响应式的,只要一更新,页面就会重新渲染。
const mutations = {
// N多个mutation
// 每个 mutation 可以接收两个参数:
// state参数:即 状态对象,由 vuex 传递
// value参数:上一环节传过来的数据,由用户传递
PLUS_ONE(state, value){
state.num += value
}
}state
state 等同于Vue当中的data(只不过这里我们不叫做数据,叫做状态),即 vuex 的data(状态)。
state 状态对象(数据对象),已经做了响应式处理的
const state = {
num : 0
}getters
getters 像是vue当作的计算属性 computed,用来将state中的数据进行加工计算,而且是响应式,不会次次都重新计算。
const getters = {
// 有很多getter,每一个getter可以看做一个计算属性
// 每一个getter方法都会自动接收一个state对象(由vuex传递)。
reversedName(state){ // 可以看做Vue中的computed
return state.username.split('').reverse().join('') // 在方法体中给出计算state的逻辑,返回值作为这个getter的值
}
}
// 注意将getter给了store
export default new Vuex.Store({
actions,
mutations,
state,
getters
})getter的使用:
与计算属性直接 this. 不同,getter 单独存放在 $store.getters 对象中,需要通过这个对象来访问 getter。如:
<h3>反转之后的用户名:{{$store.getters.reversedName}}</h3>- 使用时,将getter看成属性,而不是方法。
vuex 的使用
使用 vuex 后,vc、vm上都有一个 $store 对象,通过这个对象,来使用vuex提供的集中数据管理。
plusOne(){
// 这里的代码在实际开发中可能会比较复杂。
// 业务逻辑复杂,代码比较多。
// 如果你将这些代码放到这里的话,这些业务逻辑代码无法得到复用。
// 无法在其他组件中使用,在其他组件中使用的时候,你还需要把这些代码再写一遍。
// 交给plusOne这个action去处理。
this.$store.dispatch('plusOne', value)
// dispatch是vuex的API。调用这个方法之后,store对象中的plusOne这个action回调函数会被自动调用。
// dispatch:分发
// 业务逻辑简单时,也可以在方法内处理完后,直接交给给PLUS_ONE这个mutation去更新
this.$store.commit('PLUS_ONE', value)
}流程:
- 如果业务逻辑非常简单,也不需要发送 AJAX 请求的话,可以不调用 dispatch 方法,直接调用 commit 方法也是 可以的。

通常将一开始的action与提交的 mutation 起相似的名字,action小驼峰,mutation常量类型。如:saveUser --- SAVE_USER。
使用map优化
vuex 提供了几个 mapXxx 函数,用来动态生成固定的代码,方便在组件中使用 vuex。
map优化遵循局部优先原则,即:
- 组件中有同名的属性(data或computed)时,以组件的为准
- 组件中有同名的方法时,以组件中的方法为准
优化computed:mapState、mapGetters
组件中在使用 state 上的数据和 getters 上的数据时,都有固定的前缀:
this.$store.state.name
{{$store.state.name}}
this.$store.getters.reverseName
{{$store.getters.reverseName}}使用计算属性,可以简化调用:
computed : {
name(){
return this.$store.state.name
},
reverseName(){
return this.$store.getters.reverseName
}
}
// 添加计算属性后,组件内可直接使用
{{name}}
{{reverseName}}可知,可以使用 computed 优化 vuex 中state、getters的调用,而且代码具有一定的规则,故可以自动生成。
computed_name(){
return this.$store.state.name
}mapState、mapGetters 是专门负责 state、getters 对象映射工作的函数 function。使用 mapState 和 mapGetters 可以进行名称映射,自动生成上述代码,并以对象形式返回。
// 使用前需要导入
// 指定导入
import {mapState, mapGetters} from 'vuex'
// mapState(...) 返回如
{
name(){
return this.$store.state.name
}
}
// mapGetters(...) 返回如
{
reverseName(){
return this.$store.getters.reverseName
}
}生成后,可以使用 ES6 ...obj 来实现对象的重组:
// 使用前需要导入
// 指定导入
import {mapState, mapGetters} from 'vuex'
computed : {
...mapState(...),
...mapGetters(...)
}参数设置:
// mapState、mapGetters 允许的参数相同。
// 1. 对象式:接受一个obj作为参数。
// 这个obj的每个键值对生成一个 method
{
computed_name : 'name',
// ...
}
// 2. 数组式:接受一个arr作为参数。
// 这个arr的每个 ele 作为 computed_name 和 name
["name",...] // 'name' 以 vuex为准,不要自定义优化methods:mapActions、mapMutations
和优化 computed 类似,mapActions、mapMutations 是用来生成 action调用、mutation调用的方法的函数 function 。
action调用、mutation调用也有着固定的格式:
method_action(value){
this.$store.dispatch('action', value)
}
method_mutation(value){
this.$store.commit('mutation', value)
}使用 mapActions、mapMutations 函数,可以自动生成这些代码,并以对象形式返回:
// 使用前先导入
import {mapMutations, mapActions} from 'vuex'
// mapActions (...)
{
method_action(value){
this.$store.dispatch('action', value)
}
}
// mapMutations(...)
{
method_mutation(value){
this.$store.commit('mutation', value)
}
}
// 使用 ES6 语法进行对象合并
methods : {
...mapActions (...),
...mapMutations(...)
}参数设置:
// mapActions、mapMutations 允许的参数相同。
// 1. 对象式:接受一个obj作为参数。
// 这个obj的每个键值对生成一个 method
{
method_name : 'action',
method_name : 'mutation'
// ...
}
// 2. 数组式:接受一个arr作为参数。
// 这个arr的每个 ele 作为 method_name 和 'action'/'mutation'
['action','mutation'...] // 'action'/'mutation' 以 vuex为准,不要自定义vuex 模块化开发
vuex 是进行集中数据管理的。有时,一组数据(state、getters)、actions、mutations 是专门为某个功能实现的,vuex支持将这些配置作为一个模块来实现,在需要的组件中,只要关注这个模块即可,这就是 vuex 模块化开发。
vuex 模块化开发实际上就是抽离出部分的 state、getters、actions、mutations,单独作为一个对象(即模块),vuex 支持导入这一的对象注册为模块,作为vuex配置,实现vuex的模块化开发。
const A = {
actions : {
// ...
},
mutations : {
// ...
},
state : {
// ...
},
getters : {
// ...
}
}
export default new Vuex.Store({
// 使用 modules 配置项注册模块
modules : {
// aModule是a模块的名字
aModule : A
// 其他模块 ...
}
})使用模块化开发,允许我们将一个模块在另外的js文件中提供。这也是建议的方式。
// A.js
export default {
// ...
}
// 导入模块
import A from 'A.js'
export default new Vuex.Store({
// 使用 modules 配置项注册模块
modules : {
// aModule是a模块的名字
aModule : A
// 其他模块 ...
// 模块名 : 模块配置对象
}
})vuex 对各个模块的处理
命名空间:
const A = {
namespaced : true | false, // 默认 false
// ...
}不开启命名空间的模块,会合并配置项(?),如同名的action在调用时会一并执行。
建议开启命名空间,开启命名空间后,模块名即 modules配置项中的 key,如 aModule。
开启命名空间下各个配置项的处理:
各个模块的state配置项:
A.state ---- $store.state.aModule
各个模块的getters配置项:
A.getters.getter ---- $store.getters['aModule/getter']
各个模块的actions配置项:
A.actions.action ---- $store.dispatch('aModule/action')
各个模块的mutations配置项:
A.mutations.mutation ---- $store.commit('aModule/mutation')
模块化开发的map优化
map优化支持模块化开发,只需要在mapXxx函数加上一个模块名参数即可:
// 非模块化开发:
mapXxx(map配置对象)
// 模块化开发:
mapXxx('模块名',map配置对象)