Vue.js通过神奇宝贝#3 Vuex进行了解释:状态管理

这是我的教程系列中的第三篇文章,该文章试图通过从Pokemon中重新创建战斗场景来解释Vue.js概念。

原始教程
#1单个文件组件
#2攻击:$ refs,承诺和事件总线
#3 Vuex:状态管理
#4损害计算
#5转场和动画

在本文中,我们将以另一种方式开始处理我们的状态。

让我们继续上一教程的基于事件的实现:

GitHub –第二章活动中的learning-vue-through-pokemon
learning-vue-through-pokemon –此仓库包含我的教程系列“通过pokemon学习Vue.js”的代码github.com

在前面的文章中,我们讨论了隔离状态,即每个组件随其携带的数据。 这对于小型应用程序非常有用,但是当您的应用程序开始增长时,您很快就会注意到您的数据方法正在填充,这使得查看包含的数据变得更加困难。

我们的神奇宝贝应用程序仍然很小,但是一旦我们开始添加一个更传统的攻击系统,它就会迅速增长,当我们添加更多神奇宝贝和物品时,如果将所有存储的数据保存在一个组件中,它将变得难以管理。

我们的主要重点是分离数据,同时仍然保持所有内容的反应性和逻辑性。 最好通过通用标准,这样朋友或同事就可以在需要时加入。

输入Vuex,它是Vue.js应用程序的状态管理库。 它充当应用程序中所有组件的集中存储,其规则确保状态只能以可预测的方式进行更改。

这带来了很多好处,您应该注意的一件事是,您将无法直接更改Vuex状态,而不同于本地状态,以确保可预测性。

相反,您可以将变异提交给状态树或调度动作

突变是直接更改状态树特定部分的功能。

动作是要提交突变的,它们具有更异步的性质。 一个动作可以向您的服务器发出请求,从其响应中获取所需的数据,然后提交所需的内容。 在最简单的用途中,它可以用于提交多个突变。

但是,等等,缺少一些东西,计算属性呢?
Vuex提供吸气剂作为替代。

检索吸气剂比计算属性要冗长一些,但是我个人并不介意这种折衷。

注意:通常,您应该假定不应直接访问商店中定义的所有内容。 有包装器。

我的意思是,在动作,吸气剂或变异中,您不应尝试通过“ this ”访问状态,吸气剂,变异或行为。

让我们重新考虑应用程序的状态并将其转换为Vuex。

新数据结构

让我们从App.vue开始, 此刻 ,我们将玩家和对手的宠物小精灵分组并进行了硬编码。

我们将其更改为拥有pokedex并从该列表中选择2个pokemon。 这也会影响口袋妖怪组件。

我们还将希望将fightOptions计算属性分离为一个吸气剂。
我们将添加一个变异,使我们能够更改玩家或对手的HP。
最后,必须重置所有口袋妖怪的生命值。

由于我们将数据提取到全球存储中,因此我们无需将神奇宝贝分配给神奇宝贝组件,我们只需在组件本身中检索它即可。

Pokemon.vue中,我们将要更改任何尝试更改父组件状态的语句。 这意味着我们必须创建一个转换器来处理HP更改。

很好,所有这些,但让我们将其转换为实际代码。

让我们加入vuex

定义商店

在等待安装的过程中,让我们创建一个’ store ‘文件夹,这是我们定义Vuex存储的地方。
在其中,我们还将添加一个“ data ”文件夹,并在其中创建pokedex.js

随意添加任何您想要的宠物小精灵,我使用了laplappedia的第一代图表进行统计和攻击。

让我们回到“商店”文件夹,进入定义状态。

我们将创建一个index.js文件,在这里我们将导入Vuex并将其与Vue连接。

接下来,我们将使用所需的状态,获取器,变异和操作来定义商店:

还记得我说什么都不要直接访问吗?

我们的每个吸气剂和变异方法将始终将状态作为其第一个参数。 这将始终是我们定义的状态的最新版本。

我们定义的操作将获得分配给状态的上下文,这意味着我们实际上获得了对商店的引用。 我们可以通过此操作以及其他操作,变异和获取方法来访问状态。

如果我们想检索或更改任何内容,则必须通过第一个参数来完成。

大多数评论都说明得足够多,但是我将对象分解用于setHPreset

这样做的原因是因为突变仅获得2个参数。
如果要分配更多数据,则必须将其分组在一个对象中。
对象分解是显示所需属性的好方法。

胶入

现在我们已经定义了商店,让我们使用它。

现在该打开main.js了 ,我们将导入商店并将其分配给我们的根Vue定义。

分配存储后,您可以从分配给它的实例以及每个子实例(组件)通过this。$ store访问它。

进入商店

我们可以访问我们在商店中定义的任何内容, 声明获取器非常简单,可以通过commit调用变异

  • 状态:this。$ store.state。 属性
  • 吸气剂:this。$ store.getters。 属性
  • 突变:this。$ store.commit(’ 突变 ‘,有效载荷)
  • 操作:this。$ store.dispatch(’ action ‘,有效负载)

记住,我们不能在状态和获取方法上设置值,这就是突变和动作的目的。

您可以如上所述引用状态和获取方法,但是也可以将它们映射为计算属性,这样您就可以像以前那样在Vue实例中引用它们。

突变和动作也是如此,您可以在Vue实例的方法中引用它们。

您最终将得到如下结果:

可以,但是Vuex附带了一些可以减少我们代码的助手。 mapStatemapGetters,mapMutationsmapActions

这些帮助器的参数使用相同的覆盖区,我将向您展示一些mapStatemapGetters的示例:

我在这里使用传播运算符是因为这些函数返回一个对象,这两个对象都需要合并到计算的属性对象中。

实施商店

首先打开App.vue,首先摆脱pokemon组件上的pokemon属性

与上一个示例一样,在脚本标签上,导入所需的Vuex帮助器。

我们将从清理数据方法开始,并删除所有内容,直到剩下BattleTextBattleOptionsmenu为止。

我们将映射所需的计算属性( playerplayerAttacks )。

在此过程中,让我们将所有引用this.player.pokemon.name的字符串更改为文字字符串,这样它们就更干净了。

我们还将在我们的方法中将reset动作映射为resetPokemon ,并替换直接重置神奇宝贝HP的旧代码。

最后,我们还需要找到一种方法来实际设置玩家和对手的宠物小精灵。

Vue.js具有各种生命周期挂钩,我们已经在Vue实例定义上使用了一个挂载方法,用于设置事件监听器。

我们将使用create钩子来设置神奇宝贝。 通过在此钩子中执行此操作,我们将确保在安装App.vue (在DOM中显示)之前设置好神奇宝贝。 这也意味着我们要先设置全局存储,然后才能通过我们设置的计算属性访问全局存储。

如您在上面的代码段中所见,我们将创建的方法放置在我们现有的已挂载方法的上方。

现在我们的战斗阶段已经准备好,让我们进入Pokemon.vue

让我们看一下待办事项清单:

  • 让我们移除神奇宝贝道具,不再需要了
  • 我们还将为本地宠物小精灵(该组件为其设置的宠物小精灵)及其对手设置计算属性。
  • 因为我们切换到了pokemon.images {front,back}结构而不是字符串所以pokemon image:src需要更改。 我们将为此设置一个计算属性。
  • this.pokemonthis.opponent的所有引用需要替换。
  • 对口袋妖怪HP所做的更改需要更改为使用setHP mutator。
  • 我们还需要更改HP条的宽度的计算方式,因为口袋妖怪极有可能获得100 HP的统计数据。

在数据方法下,您可以看到我将对手属性重命名为otherPokemon ,是因为我使用状态映射从计算出的属性下的全局状态中检索对手数据。

您可以看到我们从全局状态中将2个属性映射到计算出的属性下:

  1. 本地映射到分配给此组件的口袋妖怪。
  2. 对手会映射到正在战斗的宠物小精灵。

不要忘记,我们在商店中将这两个属性定义为带有hp属性(通过攻击降低的hp)和存储pokemon定义的pokemon属性的对象。

还添加了image属性来决定使用哪种图像(对手需要从正面显示口袋妖怪的图像,而玩家的口袋妖怪则需要从背面显示)。

在方法下,我们映射了setHP mutator以便于访问,并在Attack方法中实现了该方法,我们在该方法中直接更改了对手的HP。

为了准备下一篇文章,我还创建了一个calculateDamage方法,当前该方法仅返回攻击的力量,且未发生变化。 但是稍后我们将要基于统计信息添加一些计算。

还记得我们在全球商店中定义的吸气剂吗? 对手 进攻球员进攻

在pickRandomAttack中,我们使用的是getter,我们需要从本地宠物小精灵中检索攻击名称列表。

就是这样,我们已经成功淘汰了大部分州,并将其存储在全球范围内。

与往常一样,您可以在github上找到代码:

GitHub –第三章:learning-vue-through-pokemon
learning-vue-through-pokemon –此存储库包含我的教程系列“通过pokemon学习Vue.js”的代码github.com

在下一篇文章中,我们将重点介绍传统的神奇宝贝游戏如何根据神奇宝贝的统计信息和类型来计算伤害。