vuex 概述
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
利用 vuex 集中管理数据,可以实现组件之间高效的数据共享,提高开发效率。并且,在 vuex 中存储的数据是响应式的,保证了数据与页面的同步。
在 vue 项目中使用 vuex
> 安装 vuex 依赖包
npm install vuex --save
> 导入 vuex 创建 store 并向外共享
新建 src / store / index.js 文件,写入如下代码:
import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({state: {},mutations: {},actions: {},modules: {}})
> 将 store 对象挂载到 vue 实例中
在 main.js 文件中挂载 store 对象
import Vue from 'vue'import App from './App.vue'import store from './store'Vue.config.productionTip = falsenew Vue({store,render: h => h(App)}).$mount('#app')
vuex 核心概念
vuex 核心概念有以下几种,下面将逐一介绍:
> State
state 提供唯一的公共数据源,所有共享数据都要统一存放到 store 对象的 state 中存储。
import Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({state: {count: 0}})
组件中访问 state 数据第一种方式
利用this.$store.state
直接调用
<template><div><h3>当前最新的 count 值为:{{ this.$store.state.count }}</h3></div></template>
组件中访问 state 数据第二种方式
从 vuex 中按需导入mapState
函数,将全局数据映射为当前组件的计算属性
<template><div><h3>当前最新的 count 值为:{{ count }}</h3></div></template><script>import {mapState } from 'vuex'export default {data() {return {}},computed: {...mapState(['count'])}}</script>
> Getter
getter 用于对 store 中的数据进行加工处理形成新数据,可以将 getter 理解为 store 的计算属性。
// src/store/index.jsimport Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({state: {count: 0},getters: {showNum(state) {return `当前最新数量: ${state.count} `}},})
组件中使用 getters 的第一种方式
在组件中,可以利用this.$store.getters.名称
来直接使用。
<template><div><h3>{{ this.$store.getters.showNum }}</h3></div></template>
组件中使用 getters 的第二种方式
在组件中,导入mapGetters
函数,将指定的 getters 映射为当前组件的计算属性。
<template><div><h3>{{ showNum }}</h3></div></template><script>import {mapState, mapGetters } from 'vuex'export default {data() {return {}},computed: {...mapState(['count']),...mapGetters(['showNum'])}}</script>
> Mutation
mutations 中定义用于变更 state 数据的函数。在 vuex 中,只能通过 mutation 变更 store 中的数据,不可以直接操作 store 中数据,利于集中监控数据的变化。
mutation 对象中函数的第一个参数为 state ,也可以有第二个参数 payload 即自定义参数。
需要注意:mutations 中不能定义异步函数(如 setTimeout ),必须是同步函数。
// src/store/index.jsimport Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({state: {count: 0},mutations: {add(state) {state.count++},addN(state, step) {state.count += step}}})
组件中使用 mutations 对象方法第一种方式
在组件中,需要使用this.$mit
调用 mutations 中对象方法函数。
<template><div><h3>当前最新的 count 值为:{{ $store.state.count }}</h3><button @click="btnHandler1">+1</button><button @click="btnHandler2">+N</button></div></template><script>export default {data() {return {}},methods: {btnHandler1() {this.$mit('add')},btnHandler2() {this.$mit('addN', 3)}}}</script>
触发 mutations 中函数的第二种方式
从 vuex 中按需导入mapMutations
函数,将指定的 mutations 中函数映射为当前组件的 methods 函数。
<template><div><h3>当前最新的 count 值为:{{ count }}</h3><button @click="sub">-1</button><button @click="subN(3)">-N</button></div></template><script>import {mapState, mapMutations } from 'vuex'export default {data() {return {}},computed: {...mapState(['count'])},methods: {...mapMutations(['sub', 'subN'])}}</script>
> Action
actions 对象用于处理异步任务。在 action 中通过触发 mutations 中函数的方式间接变更数据。
actions 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此可以使用mit
调用 mutations 对象的函数来变更数据。
// src/store/index.jsimport Vue from 'vue'import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({state: {count: 0},mutations: {add(state) {state.count++}},actions: {addAsync(context) {setTimeout(() => {mit('add')}, 1000)}}})
组件中使用 actions 对象方法的第一种方式
在组件中,actions 对象中方法函数需要使用this.$store.dispatch
调用。
<template><div><h3>当前最新的 count 值为:{{ $store.state.count }}</h3><button @click="btnHandler">+1 Async</button></div></template><script>export default {data() {return {}},methods: {// 异步自增btnHandler() {this.$store.dispatch('addAsync')}}}</script>
组件中 actions 对象方法的第二种方式
在组件中,从 vuex 中按需导入mapActions
函数,将指定的 actions 中函数映射为当前组件的 methods 函数。
<template><div><h3>当前最新的 count 值为:{{ count }}</h3><button @click="addAsync">+1 Async</button></div></template><script>import {mapState, mapActions } from 'vuex'export default {data() {return {}},computed: {...mapState(['count'])},methods: {...mapActions(['addAsync'])}}</script>
> Module
由于我们将所有的内容都写在了src/store/index.js
文件中,当应用变得非常复杂时,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、mutations、actions、getters 单独封装为一个子模块moduleAdd
,将其单独拎出来。
除此之外,还可将子模块的 state、mutations、actions、getters 再细分为单独的文件。
// src/store/index.jsimport Vue from 'vue'import Vuex from 'vuex'import moduleAdd from './moduleAdd/index.js'Vue.use(Vuex)export default new Vuex.Store({modules: {moduleAdd}})
子模块moduleAdd
如下命名空间
默认情况下,模块内部的 action、mutation 和 getter 是注册在全局命名空间的,这样使得多个模块能够对同一 mutation 或 action 作出响应。如果希望你的模块具有更高的封装度和复用性,此时就用到了命名空间这个概念。
通过在模块中添加namespaced: true
的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。
组件中引入带命名空间的数据的各种方式、命名空间详细介绍可阅读此文 >> Vuex 命名空间 namespaced 介绍
<template><div><h3>{{ showNum }}</h3><button @click="add">+1</button><button @click="addN(3)">+N</button></div></template><script>import {mapMutations, mapGetters } from 'vuex'export default {computed: {...mapGetters({showNum: 'moduleAdd/showNum' })},methods: {...mapMutations({add: 'moduleAdd/add',addN: 'moduleAdd/addN'})}}</script>
参考
Vuex 官方文档Vuex 命名空间 namespaced 介绍
初学 vuex 的一些总结,如有错误希望大家可以指出