整体调用图
引用
1 | import Vue from 'vue' |
代码规范
所有的状态和方法都用下划线命名法命名
getters
中以get_
开头 如:get_count
mutations
中以mut_
开头 如:mut_count
actions
中以act_
开头 如:act_count
赋值要通过一下的形式修改,不要直接修改状态
1
store.commit('increment')
取值的时候不做数据处理的时候不用
getters
,直接从store.state
中取值即可
几个属性
State
state 就类似于 data 用来保存状态的
1 | this.$store.state.count; |
当一个组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState
辅助函数帮助我们生成计算属性,让你少按几次键:
1 | // 在单独构建的版本中辅助函数为 Vuex.mapState |
当映射的计算属性的名称与 state 的子节点名称相同时,我们也可以给 mapState
传一个字符串数组。
1 | computed: mapState([ |
对象展开运算符
mapState
函数返回的是一个对象。我们如何将它与局部计算属性混合使用呢?通常,我们需要使用一个工具函数将多个对象合并为一个,以使我们可以将最终对象传给 computed
属性。但是自从有了对象展开运算符 (opens new window),我们可以极大地简化写法:
1 | computed: { |
Getter
Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
1 | const store = new Vuex.Store({ |
加工处理状态的数据 返回新数据
1 | this.$store.getters.doneTodos; |
mapGetters
辅助函数仅仅是将 store 中的 getter 映射到局部计算属性:
1 | import { mapGetters } from 'vuex' |
如果你想将一个 getter 属性另取一个名字,使用对象形式:
1 | ...mapGetters({ |
Mutation
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:
1 | store.commit('increment') |
附带参数
1 | mutations: { |
调用方式
1 | store.commit('mut_increment', 10) |
传对象
1 | mutations: { |
调用方式
1 | store.commit('mut_increment', { |
或者对象方式提交
1 | store.commit({ |
你可以在组件中使用 this.$store.commit('xxx')
提交 mutation,或者使用 mapMutations
辅助函数将组件中的 methods 映射为 store.commit
调用(需要在根节点注入 store
)。
1 | import { mapMutations } from 'vuex' |
Action
官方文档:https://vuex.vuejs.org/zh/guide/actions.html
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
Action 通过 store.dispatch
方法触发:
1 | store.dispatch('mut_increment'); |
来看一个更加实际的购物车示例,涉及到调用异步 API 和分发多重 mutation:
1 | actions: { |
注意我们正在进行一系列的异步操作,并且通过提交 mutation 来记录 action 产生的副作用(即状态变更)
你在组件中使用 this.$store.dispatch('xxx')
分发 action,或者使用 mapActions
辅助函数将组件的 methods 映射为 store.dispatch
调用(需要先在根节点注入 store
):
1 | import { mapActions } from 'vuex' |
Module
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:
1 | const moduleA = { |
命名空间
默认情况下,模块内部的 action
、mutation
和 getter
是注册在全局命名空间的——这样使得多个模块能够对同一 mutation
或 action
作出响应。
如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true
的方式使其成为带命名空间的模块。
state
不受命名空间的影响
当模块被注册后,它的所有 getter
、action
及 mutation
都会自动根据模块注册的路径调整命名。
1 | const store = new Vuex.Store({ |
辅助函数
1 | import {mapState, mapMutations, mapGetters, mapActions} from "vuex"; |
使用
1 | { |
对于这个mapMutations("menuData", ["setMenuList"]
,就是使用了命名空间,menuData
是命名空间的名称,["setMenuList"]
是我们要获取的方法。
以下两种是等效的:
1 | mapMutations("aa", ["myfunc1","myfunc2"]); |
对应的调用方式
1 | this.myfunc1(); |
当使用 mapState
, mapGetters
, mapMutations
和mapActions
这些函数来绑定带命名空间的模块时,写起来可能比较繁琐:
1 | computed: { |
对于这种情况,你可以将模块的空间名称字符串作为第一个参数传递给上述函数,这样所有绑定都会自动将该模块作为上下文。于是上面的例子可以简化为:
1 | computed: { |
而且,你可以通过使用 createNamespacedHelpers
创建基于某个命名空间辅助函数。它返回一个对象,对象里有新的绑定在给定命名空间值上的组件绑定辅助函数:
1 | import { createNamespacedHelpers } from 'vuex' |
mapActions 工具函数会将 store 中的 dispatch 方法映射到组件的 methods 中。
和 mapState、mapGetters 也类似,只不过它映射的地方不是计算属性,而是组件的 methods 对象上。
我们来直接看它的实现:
1 | export function mapActions(actions) { |
可以看到,函数的实现套路和 mapState、mapGetters 差不多,甚至更简单一些,实际上就是做了一层函数包装。为了更直观地理解,我们来看一个简单的例子:
1 | import {mapActions} from 'vuex' |
经过 mapActions 函数调用后的结果,如下所示:
1 | import {mapActions} from 'vuex' |
结论
所以这就是为什么调用方法时传参第一个参数是不用传的。
修改State方式对比
- 可以直接使用
this.$store.state.变量 = xxx;
this.$store.dispatch(actionType, payload)
this.$store.commit(commitType, payload)
共同点:
都能够修改state里的变量,并且是响应式的(能触发视图更新)
不同点:
若将vue创建 store 的时候传入 strict: true
, 开启严格模式,那么任何修改state的操作,只要不经过mutation的函数,vue就会
throw error : [vuex] Do not mutate vuex store state outside mutation handlers。
使用commit提交到mutation修改state的优点:
vuex能够记录每一次state的变化记录,保存状态快照,实现时间漫游/回滚之类的操作。
官方要求最好设置严格模式,并且每次都要commit来修改state,而不能直接修改state,以便于调试等。
Mutation和Action
- Mutation必须是同步操作,只有Mutation才能正真改变State
- Action可以有异步操作,通过调用Mutation实现State的变化
状态持久化
下载依赖
1 | npm install vuex-persistedstate --save |
持久化到localStorage
引入及配置:在store下的index.js中
1 | import createPersistedState from "vuex-persistedstate" |
默认存储到localStorage
持久化到sessionStorage
想要存储到sessionStorage,配置如下
1 | import createPersistedState from "vuex-persistedstate" |
默认持久化所有state
持久化部分状态
指定需要持久化的state,配置如下
1 | import createPersistedState from "vuex-persistedstate" |