简介
Vuex是一个在Vuex商店中存储数据的库,它是Vue应用程序中状态的数据来源。这个存储空间包含一个全局状态(一组属性)和用于读取和改变状态的函数*(getters*,action和mutations)。
考虑一个场景,你想创建一个简单的Vue应用程序,让你从一个变量中添加或删除一个值,count ,就像下面的图片。

正常的过程是--首先,定义一个函数来返回我们的count 变量。
data() {
return {
count: 0
}
}
然后定义一个增量和减量函数,这样我们就可以操作count
methods: {
increment() {
this.count++;
},
decrement() {
this.count--;
}
}
虽然这种模式没有什么问题(至少在简单的应用中),但当你试图在不同的组件之间反应性地分享数据时,就会出现问题。
你可以选择使用组件props ,但考虑到现实中需要处理50-100个(或更多)组件的情况,使用props很快就会变得很乏味。
在开发大规模应用时,即有几十个组件的应用,组件之间的数据共享会变得更加复杂。这就是为什么像Vuex这样的解决方案被创造出来--使状态管理不那么痛苦。
在本指南中,我们将介绍所有你需要知道的,以开始使用Vue.js的官方状态管理库。 Vuex.
开始使用Vuex
Vuex的灵感来自于像Facebook的 Flux和React的状态管理库。 ReduxVuex的灵感来自于Facebook和React的状态管理库,其目的是在确保性能和可维护性的前提下,使Vue应用中的反应性数据的存储和交换尽可能简单。
这是通过拥有一个集中的存储来实现的,你可以从中提取数据,并将数据写入其中。没有其他方法可以获得或改变它--这使得它在许多组件上保持一致和稳定。这消除了在多个反应式组件相互交谈时经常会引起的不稳定。
根据它的文档。
"Vuex是Vue.js应用程序的状态管理模式+库。它作为应用程序中所有组件的集中存储,其规则确保状态只能以可预测的方式被改变"。
这是通过三种类型的方法实现的,对记录的状态进行操作。Getters用于从存储中获取数据,Action用于异步获取数据、处理数据和调用突变,而突变则用于改变存储中的源数据。从某种意义上说,你可以想象这样一个循环。

集中的全局状态(或其属性)通过获取器显示给用户-->应用程序调用一个动作-->动作调用全局状态的突变-->获取器用于检索新的状态并显示给用户。
通过这些元素--你可以进行稳定、可维护的状态管理。
安装Vuex
有几种方法来安装Vuex--其中大部分取决于你如何创建你的vue应用。
如果你的项目使用Vue CDN,而不是像vue-cli 或vite ,你要下载Vuex的源文件,并把它包含在你的应用程序标记中。
<script src="/path/to/vue.js"></script>
<script src="/path/to/vuex.js"></script>
如果你使用vue-cli,你可以在安装过程中直接包含Vue的官方软件包,如vue-router 和vuex 。
首先,你要创建一个新的Vue项目。
$ vue create project-name
运行这个应该会出现以下输出。

在这里,你可以用键盘导航到手动选择功能选项,以添加你的应用程序需要的所有包,包括Vuex。

另外,如果你有一个用vue-cli 或Vite创建的现有项目,但没有事先支持Vuex,你可以用npm 或yarn 来安装它。
$ npm install vuex --save
# Or yarn
$ yarn add vuex
Vuex配置
如果你用yarn 或npm 将Vuex作为一个包安装,你必须明确指示Vue将其作为一个插件使用。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
new Vue({...})
用Vuex进行集中状态管理
控件 存储是Vuex应用中所有操作的中心。它是一个反应式容器,持有整个应用程序的状态,以及从该状态集读取和写入所需的功能。此外,在存储中定义的数据或方法是通用的,这意味着你可以从你的vue应用程序的任何地方访问它们。
我们可以通过使用导入的Vuex ,轻松创建一个新的Vuex商店。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {},
mutations: {},
actions: {},
getters: {}
});
虽然它是空的--商店只是有一个空的状态、突变、动作和getters的集合。我们可以通过一个全局的this.$store 实例来访问这个存储实例!不过,在访问它之前,我们要在我们的Vue实例中注册它。
new Vue({
el: '#app',
store: store,
})
现在,我们可以用状态和函数来填充这个商店,让它对我们有用!
Vuex状态
认为Vuex 状态相当于Vue实例中的data 。然而,与data 不同,你存储在一个状态中的所有东西都是全局性的--这意味着,它不局限于一个单一的组件,可以在你的应用程序中的任何地方被访问或修改。
你可以通过简单地将属性添加到商店实例的state 字段来为状态添加条目。
const store = new Vuex.Store({
state: {
name: "John Doe",
age: 12,
details: {
city: "San Fransisco",
country: "USA",
},
},
});
在这里,我们为username,age, 和details (一个包含用户的city 和country 的对象)定义了一个状态。现在,state 的这些属性可以在全球范围内被访问!
通常情况下,你会在这里定义一些全局常数。
访问Vuex状态
检索状态值的最简单方法是在一个计算的属性中返回状态。比方说,我们想访问我们商店中的全局name 和age 状态。
computed: {
name() {
return this.$store.state.name;
},
age() {
return this.$store.state.age;
},
}
**注意:**当一个组件需要访问多个存储状态时,声明所有这些计算属性可能会变得繁琐和冗长。有一个辅助类就是为这个目的而创建的,我们将在一分钟内介绍它。
当然,这些值现在可以在我们的标记中被访问。
<template>
<div id="app">
<p>Name: {{ name }}</p>
<p>Age: {{ age }}</p>
</div>
</template>
*mapState()*助手
正如前面的例子中所看到的,声明计算属性可能会变得非常冗长。考虑到这一点,Vuex提供了一个用于生成计算型getter函数的辅助工具。它是一个状态映射器,允许你轻松地将计算的状态映射到更短的别名。
例如,让我们导入mapState() 辅助函数,并将state.name 和state.age 映射到更短的别名中。
// First - import mapState
import { mapState } from "vuex";
export default {
name: "ComponentName",
computed: mapState({
name: (state) => state.name,
age: (state) => state.age,
}),
};
获取器函数
Getter函数是用来从一个存储空间获得一个计算属性的函数。在获取一个属性时,如果需要的话,你可以选择在返回数据之前对其进行额外的过滤、验证或处理。
注意:获取器仅用于获取数据,而不是修改原始来源。虽然你可以过滤和处理你返回给用户的数据,但你不能在原地改变原始数据。
例如,假设有一个记录整数的状态。通过一个getter函数,你可以原封不动地返回数字,或者对它们进行排序,并从中切出一些数字来返回。
const store = new Vuex.Store({
state: {
myNumbers: [11, 3, 5, 1, 54, 56, ...],
},
getters: {
firstFiveSorted: (state) => {
return state.myNumbers.sort().slice;
},
},
});
这个getter现在可以在store.getters 全局对象中使用,也可以在任何组件中访问。
//...
computed: {
firstFiveSorted () {
return this.$store.getters.firstFiveSorted
}
}
不过,这也会在一段时间后变得冗长。就像你可以将状态映射到它们的别名一样,你也可以通过mapGetters() 辅助函数将getter映射到它们自己的别名。
import { mapGetters } from "vuex";
export default {
computed: {
...mapGetters({
// this example will map `myNumbers` to `this.$store.getters.firstFiveSorted`
myNumbers: "firstFiveSorted",
}),
},
};
Vuex突变
在Vuex中,修改源状态的唯一方法是通过 突变.你可能会认为它们是Vue实例中的methods 属性,但作用是修改Vuex存储中的一个状态。此外,突变是通过存储进行的,以确保变化是可预测的。
**注意:**按照惯例,突变的名字都是大写的,并且用SNAKE_CASE 。
突变将接收状态作为第一个参数,以及一个可选的有效载荷(即提交突变所需的可选参数)作为第二个参数。
const store = new Vuex.Store({
state: {
myNumbers: [11, 3, 5, 1, 54, 56]
},
mutations: {
ADD_NUMBER(state, numberToAdd) {
state.myNumbers.push(numberToAdd);
},
}
})
而且,为了调用一个突变,我们需要用突变的名字和它的有效载荷(如果存在有效载荷的话)调用store.commit() 方法。
this.$store.commit('ADD_NUMBER', 75);
调用突变的唯一方法是向存储空间提交一个变化,并传入突变的名称。
**注意:**突变的一个缺点是,它们必须是同步的,也就是说,你不能在其中执行异步操作。Vuexactions 是解决这个问题的方法,我们将在下一节讨论。
行动
行动被用来在突变提交该变化之前获取和处理数据。此外,你可以通过动作异步地进行多个突变调用,而突变本身则同步地执行。此外,行动可以调用其他行动,而不像突变必须通过commit() 方法来调用。
从某种意义上说--你可以把行动看作是突变数据的授权代理,而突变则是做最后的重活。
行动接收一个context 对象和一个可选的有效载荷作为其参数。上下文对象提供了对一些方法的访问,如context.commit() ,它允许你提交一个突变。context.state(), 和context.getters() 允许你访问商店的状态和获取器。context 对象不是商店的实例 - 它只是暴露了与商店实例相同的属性。
例如,假设我们想执行一个异步操作,每隔n 秒向myNumber 数组中添加一个随机数。
const store = new Vuex.Store({
state: {
myNumbers: [11, 3, 5, 1, 54, 56, "..."],
},
mutations: {
ADD_RANDOM_NUMBER(state) {
// Push a random number to `myNumbers` array
state.myNumbers.push(Math.floor(Math.random() * 10));
},
},
actions: {
// Using destructuring to extract only `commit()` from the `context` object
addNumber({ commit }, time) {
setInterval(() => {
commit("ADD_RANDOM_NUMBER");
}, time * 1000);
},
},
});
为了调用该操作本身,我们也要调用商店来做--通过dispatch() 函数。
store.dispatch('ADD_RANDOM_NUMBER', 10);
通过存储确保状态只以一种可预测的方式改变。
总结
在本指南中,我们已经了解了Vuex--Vue的官方状态管理存储。
Vuex存储是一个状态、获取器、突变和动作的集合。状态是用来定义全局状态属性的,而获取器是用来获取它们的。你可以将状态属性和获取器映射到更短的别名,以便更容易引用它们。变体和动作携手合作,以可控的方式改变状态属性。