文章目录
一、参考资料
二、运行环境
- Windows11
- Visual Studio Code v2022
- Node.js v16.5.01
- Vue/cli v5.0.6
- Bootstrap 5.1.3
三、Vuex@3插件
注意:这里的Vuex知识是基于Vuex版本3的。
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。对 vue 应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。
Vuex插件的GitHub地址:点击查看
适用场景:
- 多个Vue组件依赖于同一状态
- 来自不同Vue组件的行为需要变更同一状态
3.1 状态管理模式
Vue官方提供的案例:计数
new Vue({
// state 驱动应用的数据源
data () {
return {
count: 0
}
},
// view 以声明方式将 state 映射到视图
template: `
<div>{
{ count }}</div>
`,
// actions 响应在 view 上的用户输入导致的状态变化
methods: {
increment () {
this.count++
}
}
})
这个状态自管理应用包含以下三个部分:state、view、actions
以下是一个表示“单向数据流”理念的简单示意:
当应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏。
Vuex设计思路:
将Vue组件的共享状态抽取出来,以一个全局 单例模式 管理。
在这种模式下,组件树就构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为。
据官方说明, Vuex的设计借鉴了 Flux、Redux 和 The Elm Architecture
Vuex结构图:
如果拿SpringMVC架构和这张图做对比,那么会发现它们有类似的地方,如下图:
- A c t i o n s Actions Actions层负责响应请求,同时执行一些业务逻辑,类似于后端的 C o n t r o l l e r + S e r v i c e Controller+Service Controller+Service ,在 A c t i o n s Actions Actions 层通常会适用
axios
发送请求到后端获取数据,同时可以调用API
获取数据。 - M u t a t i o n s Mutations Mutations层负责进行数据的处理,类似于后端的 D A O DAO DAO 层,它会根据 A c t i o n s Actions Actions 层传来的数据对存储在 s t a t e state state层的数据进行增删改查之类的操作。
- S t a t e State State 层负责存储数据,在Vue中通常用于渲染页面。
因为Vuex插件支持所有组件共享$store
这个对象,所以每个组件都可以通过$sotre
获取到 s t a t e state state 层里的数据。
而组件可以直接获取数据,另外还可以通过 计算属性 获取到state层的数据,例如:
computed: {
studentList(){
return this.$store.state.student.studentList || []
},
},
在使用Vuex3 时,我们需要按照其设计的流程来执行,其中 M u t a t i o n s Mutations Mutations层是必须要经过的,因为Devtools调试工具会监听这一层的变化而不会监听Actions的变化。
除此之外,适用Vuex3的调用流程通常有两种:
- a c t i o n s − > m u t a t i o n s − > s t a t e actions -> mutations -> state actions−>mutations−>state
- m u t a t i o n s − > s t a t e mutations -> state mutations−>state
我们可以忽略actions,这个就和后端的Controller和Service不同了,区别在于前端的actions层主要是负责请求获取数据的,如果无需请求数据,比如:根据当前state里的数据进行筛选查询,此时就不需要请求获取数据,那么Vuex支持直接执行mutations层的代码,直接处理state的数据即可。
3.2 Vuex 核心概念和API
3.2.1 state
概念与特点:
- vuex 管理的状态对象
- 唯一,不可重复
例如:
state: {
// 若有本地缓存就读缓存,否则设置为空
studentList: JSON.parse(localStorage.getItem('studentList')) || []
}
3.2.3 actions
注: Action是Vuex运行原理图中Vue组件使用Vuex的入口,Mutation也可以是入口。
概念与特点:
- 值为一个对象,包含多个响应用户动作的回调函数
- 通过 commit() 来触发 mutation 中函数的调用, 间接更新 state
- action 提交的是 mutation,而不是直接变更状态。
- action 可以包含任意异步操作。支持AJAX、定时器等异步操作。
重点:触发 actions 中的回调函数
在组件中使用:$store.dispatch('对应的 action 回调名')
触发,例如(查询学生信息):
// search.js
actions: {
searchStuById(context, info){
// 业务逻辑比较简单,这里可以发送axios请求获取数据
context.commit('getStuById',info)
},
...
}
// Search.Vue
this.$store.dispatch('search/searchStuById', [this.searchInfo, this.allStudent])
注意:actions中的回调函数第一个参数默认为应用上下文对象,第二个参数才是通过dispatch传递的值,应用上下文对象内容如下:
这表示我们可以通过这个应用上下文对象继续 dispatch 分发,也可以commit提交到mutation等。
3.2.4 mutations
概念与特点:
- 值是一个对象,包含多个直接更新 state 的方法
- 每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。
- 有两种调用方式:1)在 action 中(由第一个参数)使用:commit(‘对应的 mutations 方法名’) 触发
- mutations 中方法的特点:1) 不能写异步代码;2) 只能单纯的操作 state
例如(根据ID查询学生信息):
mutations: {
// 根据ID查询学生
getStuById(state, info){
let id = info[0]
let studentList = info[1]
state.searchStudentList = studentList.filter((stu) => stu.id === id)
},
...
}
这里提一句,在mutation修改完数据后,state里的数据就发生改变了,那么页面里的数据是如何受到影响的呢?
因为Vuex支持所有组件共享同一个 $store
,所以最简单的做法就是可以写一个计算属性,去获取 $store
里state层的数据。例如:
computed: {
searchStudentList(){
return this.$store.state.search.searchStudentList || []
},
...
}
前端页面渲染只需要遍历计算属性的名称即可:
<ul>
<li v-for="(stu) in searchStudentList" :key="stu.id">
{
{stu.id}}, {
{stu.name}}
</li>
</ul>
3.2.5 getters
概念与特点:
- 值为一个对象,包含多个用于返回数据的函数
- 调用方式 —— $store.getters.xxx
- 可以认为是 store 的计算属性
- 类似于计算属性,getter 的返回值会根据其依赖被 缓存 起来,且只有当其依赖值 发生了改变 才会被重新计算。
- 跟之前的state、action和mutation一样,可以在任意组件中访问,例如:
// student.js
getters: {
studentCount (state){
return state.studentList.lenth
}
}
// Student.vue
computed: {
studentCount () {
return this.$store.getters.studentCount
}
}
3.3 Vuex 模块化开发
概念与特点:
- Vuex支持在modules里设置多个 module
- 一个 module 是一个 store 的配置对象
- 与每个组件(包含有共享数据)对应
如下图所示,Vuex通常可以分为不同的模块,比如这里比较简单的分为了学生模块和查询模块。
index.js
// 该文件用于创建 VueX 中最为核心的 Store
// 引入 Vue
import Vue from 'vue'
// 安装vuex@3 npm i vuex@3
import Vuex from 'vuex'
import search from './search'
import student from './student'
Vue.use(Vuex)
// 创建 Store并导出
export default new Vuex.Store({
modules: {
search, student}
})
search.js
export default {
namespaced: true,
// Actions —— 用于响应组件中的动作
actions: {
... },
// Mutations —— 用于操作数据(state)
mutations: {
... },