Vue Vuex
本文将介绍 Vuex,在 Vue 中用于集中式管理数据的工具。
一、什么是 Vuex?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。
- 状态,又称为数据
- Vuex 负责在 Vue 应用中进行数据管理
- 有时候,多个组件需要访问相同的数据,此时需要考虑以下问题:
- 组件应该都能获取数据
- 组件应该都能修改数据
- 数据应该是响应式的,能够在多个组件之间同步的
- Vuex 将 Vue 应用中需要共享的数据抽取,放置于一个全局的单例的容器之中,因此,各个组件都能够以相同的方式访问和修改相同的数据
二、安装
1. 下载或用 CDN 引入
1 |
|
2. NPM
安装
1 |
|
注册方法 1
在 main.js 中:
1 |
|
注册方法 2(更好)
创建 store 文件夹,在其中创建 index.js 文件
1 |
|
在 main.js 中引入
1 |
|
三、简单使用
创建 store 文件夹,在其中创建 index.js 文件,注册 store ,放置数据并向外暴露:
1 |
|
在 main.js 中引入:
1 |
|
在组件中获取 store 中的数据:
1 |
|
不应该直接通过
$store.state.属性名
修改属性,应该提交并让 Vuex 处理,以便正确地追踪每一个属性的变化情况
四、State
1. 单一状态树
Vuex 使用单一状态树,简单来说,数据都放置于一个全局的单例的容器之中,每个应用仅包含一个 store 实例。
这种做法将有利于监听数据状态,也有利于管理与维护。
2. 访问状态
(1) 直接访问
1 |
|
(2) 通过计算属性
官方推荐使用计算属性获取状态
1 |
|
3. mapState
(1) 说明
mapState()
方法的作用是:帮助程序员将 state 映射到计算属性中。
它接收一个对象,根据对象中的属性生成可以被 computed 识别的对象,并返回。
(2) 用法
1 |
|
(3) 和其它计算属性共存
ES6 返回的是一个对象,为了与其它计算属性共存,可以利用 ES6 的扩展运算符。
1 |
|
五、Getters
1. 说明
有时候,全局数据需要进行 “加工” 以获得想要的数据。
有一种解决方法是在组件中加工(在组件中使用计算属性访问全局数据,加工后返回)。
但如果有多个组件需要用到 “加工” 后的属性,更好的解决方式是将加工放置到 Vuex 中。
Vuex 提供了 Getters,它可以类比计算属性,属性会在加工后返回,并且返回值会缓存,当依赖值改变后才重新计算。
使用 Getters 也有其它好处,类比 Bean 中的 Getter,可以让状态被获取的方式单一化且便于后期维护
2. 基本使用
(1) 语法
1 |
|
(2) 示例
1 |
|
3. 返回属性的 Getter
(1) 访问
1 |
|
(2) 参数
不允许直接向 getters 传递参数,但 getters 可以接收两个参数,其中:
state:通过 state ,使 getters 能够访问 state 中的属性,访问方式为:
1
state.状态名
getters:通过访问其它派生属性,从而避免重复计算,使代码更加简洁
4. 返回方法的 Getter
(1) 作用
Getter 不仅可以从 state 和 getters 中获取,而且还可以通过方法的方式临时获取组件提供的其它参数,从而进行更复杂的更灵活的计算。
(2) 做法
让 Getter 返回一个方法,在方法中获取参数、计算结果并返回。
1 |
|
(3) 示例
1 |
|
(4) 不会缓存
返回方法的 Getter 和返回属性的 Getter 不同,其值并不会缓存,每次都重新计算。
5. mapGetter
和 mapState 类似,将 getter 映射到计算属性之中。
六、mutations
1. 作用
用于修改 store 中的 state。
2. 注册 mutation
(1) 语法
1 |
|
state 并非从调用处传入,只需要在形参列中写上即可
(2) 示例
1 |
|
(3) 载荷
可以填入额外的参数,这个额外的参数被称为载荷(payload)。
1 |
|
由于载荷只能有一个,因此最好将载荷设为对象,以便传递多个参数。
1 |
|
3. 调用 mutation
(1) 说明
不应该直接修改 state 中的数据,也不能够直接调用 mutation ,应该使用 commit 方法,并向 store 传递方法名,从而调用对应的方法修改数据。
(2) 语法
1 |
|
(3) 传入载荷
1 |
|
(4) 以对象形式传入参数
可以在调用 commit 方法时,以对象形式传入参数。
此时,
- type 参数是必须的,填入方法名
- 将载荷中的属性依次填入参数对象中
1 |
|
4. 响应式规则
Vuex 的 store 中的属性是响应式的,但也需要遵守一些要求:
响应式的属性必须在最开始就进行初始化
需要为对象/数组添加新属性时,应该用
Vue.set
1
Vue.set(对象/数组, 属性名/数组下标, 值)
需要为对象/数组删除属性时,应该用
Vue.delete
1
Vue.delete(对象/数组, 属性名/数组下标)
不应该直接修改属性,应该通过 mutation (否则 Vue 将无法监听)
5. 必须是同步函数
mutation 必须是同步函数,mutation 只能够监听同步事务。如果需要处理异步操作,应该使用 actions 。
6. mapMutations
和 mapState 类似,将 mutations 映射到 methods 之中。
七、Actions
1. Actions 与 Mutations 的不同
- Actions 提交 Mutation,通过 Mutation 来修改属性,并不直接修改属性
- Actions 可以包含异步操作
2. 注册 Action
(1) 语法
1 |
|
(2) 参数
context 为 action 的默认参数,它和 store 并不等同,但拥有相同的内容。
(3) 载荷
actions 能够使用载荷,并且也能够以对象形式传入参数。
3. 调用 Action
(1) 语法
1 |
|
(2) 传入载荷
1 |
|
(3) 以对象形式传入参数
1 |
|
4. 异步 Action
Action 可以是异步的。
Action 可以返回 Promise,并且该 Promise 会被 store.dispatch()
返回。
1 |
|
5. mapActions
和 mapState 类似,将 actions映射到 methods 之中。
八、Modules
1. 什么是 Modules?
由于使用单一状态树,整个应用的所有共享属性都将放置在一个对象中,当应用十分复杂时,对象可能变得非常臃肿。
为了解决这一问题, Vue 允许我们将 store 分割成模块,每个模块将拥有自己的 state、getters、mutations、actions、modules。
2. 参数变化
- getter 接收的参数将由全局状态对象变为局部状态对象
- mutations 接收的参数将由全局状态对象变为局部状态对象
- actions 仍然接收到 content,但 content 不再等同于全局状态对象,而是通过
content.state
获取局部状态对象,通过content.rootState
获取全局状态对象
3. State 的访问
1 |
|
4. Action、Mutation 和 Getter 的访问
(1) 默认方式
默认情况下,Action、Mutation 和 Getter 会注册在全局命名空间中。
即直接在全局就可以找到它们
此时,无需指定模块名就可以访问 Action、Mutation 和 Getter,访问方式和此前相同。
1 |
|
(2) 命名空间方式
可以通过 namespaced: true
的方式使模块称为带命名空间的模块。
此时,需要指定模块名才能访问 Action、Mutation 和 Getter。
1 |
|
九、项目结构
可以将文件从 store/index.js 中抽离出去,方便管理与维护。
1 |
|