Vuex 是一个专为 Vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。
一、vuex 安装
npm install vuex --save
二、导入 vuex 包
import Vuex from 'vuex'Vue.use(Vuex)
三、创建store 对象
const store = new Vuex.Store({ state:{ count:0 }})
四、将store对象挂载到vue实例中
new vue({ el:'#app', render:h=>h(app), router, // 将创建的共享数据对象,挂载到vue实例中 // 所有的组件,就可以直接从store中获取全局的数据了 store })
五、vuex中的核心概念
1、state
state提供唯一的公共数据源,所有共享的数据都要统一放到store的state中进行存储。
// 创建store数据源,提供唯一公共数据 const store = new Vuex.Store({ state:{ count:0 } }) // 组件访问state中数据的第一种方式: this.$store.state.全局数据名称 // 组件访问state中数据的第二种方式(通过辅助函数): // 1、从vuex中按需导入mapState函数 import {mapState} from 'vuex' // 通过刚才导入的mapState函数,将当前组件需要的全局数据,映射为当前组件的computed计算属性 // 2、将全局数据,映射为当前组件的计算属性 computed:{ ...mapState(['count']) // 或者 ...mapState({ current: (state) => state.tab.currentMenu, }), }
2、Mutation
Mutation用于变更store中的数据
1)、只能通过mutation变更store数据,不可以直接操作store中的数据。
2)、通过这种方式虽然操作起来稍微繁琐一些,但是可以集中监控所有数据的变化。
// 定义Mutation const store = new Vuex.Store({ state:{ count:0 }, mutations:{ add(state){ // 变更状态 state.count++ } } }) // 触发mutation methods:{ handel(){ // 触发 mutations 的第一种方式 this.$store.commit('add') } }
// 可以在触发 mutations 是传递参数 // 定义Mutation const store = new Vuex.Store({ state:{ count:0 }, mutations:{ addN(state,step){ // 变更状态 state.count += step } } }) // 触发 mutation methods:{ handel2(){ // 在调用 commit 函数,触发 mutations 时携带参数 this.$store.commit('add',3) } }
触发mutation的第二中方式:
// 1)、从 vuex 中按需导入 mapMutations 函数 import { mapMutations } from 'vuex'// 通过刚才导入的mapMutations函数,将需要的mutation函数,映射为当前组件的methods方法: methods:{ ...mapMutations(['add','addN']) }
3、Action
Action用于处理异步任务
如果通过异步操作变更数据,必须通过Action,而不能使用Mutation,但是在Action中还是要通过触发Mutation的方式间接变更数据。
// 定义Action const store = new Vuex.Store({ state:{ count:0 }, mutations:{ add(state){ // 变更状态 state.count ++ } }, actions:{ addAsyns(context){ setTimeout(()=>{ contexxt.commit('add') },1000) } } })// 触发Action methods:{ handel(){ // 触发 actions 的第一种方式 this.$store.dispatch('addAsync') } }
触发actions异步任务时携带参数:
// 定义Action const store = new Vuex.Store({ state:{ count:0 }, mutations:{ addN(state,step){ // 变更状态 state.count += step } }, actions:{ addAsyns(context,step){ setTimeout(()=>{ contexxt.commit('add',step) },1000) } } })// 触发Action methods:{ handel(){ // 在调用 dispatch 函数,触发 actions 时携带参数 this.$store.dispatch('addAsync',5) } }
触发actions的第二种方式:
// 1)、从 vuex 中按需导入 mapActions 函数 import { mapActions } from 'vuex'// 2)、通过刚才导入的 mapActions 函数,将需要的actions 函数,映射为当前组件的methods方法: methods:{ ...mapActions(['addAsync','addNAsync']) }
4、Getter
getter 用于对store中的数据进行加工处理形成新的数据。类似于计算属性computed
1)、getter可以对store中已有的数据加工处理之后形成新的数据,类似vue的计算属性。
2)、store中的数据发生变化,getter的数据也会跟着变化。
// 定义getter const store = new Vuex.Store({ state:{ count:0 }, mutations:{ addN(state,step){ // 变更状态 state.count += step } }, getters:{ snowNum:state=>{ return '当前最新的数量是【'+ state.count +'】' } } })
// 使用getters的第一种方式: this.$store.getters.名称 // 使用getters的第二种方式: import {mapGetters} from 'vuex' computed:{ ...mapGetters(['showNum']) }
5、Module
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:
const moduleA = { state: { ... }, mutations: { ... }, actions: { ... }, getters: { ... }}const moduleB = { state: { ... }, mutations: { ... }, actions: { ... }}const store = new Vuex.Store({ modules: { a: moduleA, b: moduleB }})store.state.a // -> moduleA 的状态store.state.b // -> moduleB 的状态
在项目中 module 的使用:
store/index.js :
import Vue from 'vue'import Vuex from 'vuex'// 引入tab.jsimport tab from './tab.js'Vue.use(Vuex)export default new Vuex.Store({ modules: { tab }})
store/tab.js :
export default { state: { menu: [], // 点击的菜单 currentMenu: null }, mutations: { selectMenu(state, val) { // state.currentMenu = val; val.name === 'home' ? state.currentMenu = null : state.currentMenu = val; } }, actions: {}, modules: {}}
六、vuex 数据在页面刷新后数据丢失问题
解决方法:在APP.vue文件的created生命周期中加入以下代码即可:
//在页面加载时读取sessionStorage里的状态信息 if (sessionStorage.getItem("store")) { this.$store.replaceState( Object.assign( {}, this.$store.state, JSON.parse(sessionStorage.getItem("store")) ) ); } //在页面刷新时将vuex里的信息保存到sessionStorage里 window.addEventListener("beforeunload", () => { sessionStorage.setItem("store", JSON.stringify(this.$store.state)); });
总结:
1、vuex主要包括以下几个模块:
State:定义了应用状态的数据结构,可以在这里设置默认的初始状态。
Getter:允许组件从 Store 中获取数据,mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性。
Mutation:是唯一更改 store 中状态的方法,且必须是同步函数。
Action:用于提交 mutation,而不是直接变更状态,可以包含任意异步操作。
Module:允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中。
2、什么情况下使用 Vuex?
如果应用够简单,最好不要使用 Vuex,一个简单的 store 模式即可
需要构建一个中大型单页应用时,使用Vuex能更好地在组件外部管理状态
3、Vuex和单纯的全局对象有什么区别?
Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
4、为什么 Vuex 的 mutation 中不能做异步操作?
Vuex中所有的状态更新的唯一途径都是mutation,异步操作通过 Action 来提交 mutation实现,这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
每个mutation执行完成后都会对应到一个新的状态变更,这样devtools就可以打个快照存下来,然后就可以实现 time-travel 了。如果mutation支持异步操作,就没有办法知道状态是何时更新的,无法很好的进行状态的追踪,给调试带来困难
5、vuex的action有返回值吗?返回的是什么?
store.dispatch 可以处理被触发的 action 的处理函数返回的 Promise,并且 store.dispatch 仍旧返回 Promise
Action 通常是异步的,要知道 action 什么时候结束或者组合多个 action以处理更加复杂的异步流程,可以通过定义action时返回一个promise对象,就可以在派发action的时候就可以通过处理返回的 Promise处理异步流程。
一个 store.dispatch 在不同模块中可以触发多个 action 函数。在这种情况下,只有当所有触发函数完成后,返回的 Promise 才会执行。
6、为什么不直接分发mutation,而要通过分发action之后提交 mutation变更状态?
mutation 必须同步执行,我们可以在 action 内部执行异步操作
可以进行一系列的异步操作,并且通过提交 mutation 来记录 action 产生的副作用(即状态变更)
7、从vuex中获取的数据能直接更改吗?
从vuex中取的数据,不能直接更改,需要浅拷贝对象之后更改,否则报错;
8、Vuex的严格模式是什么,有什么作用,怎么开启?
在严格模式下,无论何时发生了状态变更且不是由mutation函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。
在Vuex.Store 构造器选项中开启,如下:
const store = new Vuex.Store({ strict:true,})
9、mutation和action有什么区别
action 提交的是 mutation,而不是直接变更状态。mutation可以直接变更状态
action 可以包含任意异步操作。mutation只能是同步操作
提交方式不同
action 是用this.store.dispatch('ACTION_NAME',data)来提交。mutation是用this.$store.commit('SET_NUMBER',10)来提交
接收参数不同,mutation第一个参数是state,而action第一个参数是context,其包含了
{ state, // 等同于 `store.state`,若在模块中则为局部状态 rootState, // 等同于 `store.state`,只存在于模块中 commit, // 等同于 `store.commit` dispatch, // 等同于 `store.dispatch` getters, // 等同于 `store.getters` rootGetters // 等同于 `store.getters`,只存在于模块中}
10、在v-model上怎么用Vuex中state的值?
需要通过computed计算属性来转换。
"message">// ...computed: { message: { get () { return this.$store.state.message }, set (value) { this.$store.commit('updateMessage', value) } }}