《行动中的Vue.js》一书

图片 嗨,habrozhiteli! 本书的目的是为您提供知识,使您可以毫不犹豫地使用该库加入任何项目。 本书面向有兴趣学习Vue.js并具有JavaScript,HTML和CSS经验的所有人。 您不需要对此领域有深入的了解,但是了解基本知识(例如数组,变量,循环和HTML元素)将不会受到损害。

切口下方是Vuex章节形式的一段,描述:什么情况? 使用吸气剂; 实施突变; 增加动作; 使用Vuex辅助方法; 模块和项目设置。

10.1。 为什么我们需要Vuex


Vuex库管理状态。 它集中存储它,使访问它的任何组件变得容易。 状态是支持应用程序的信息或数据。 这很重要,因为我们需要一种可靠且可理解的机制来处理此信息。

如果您已经具有使用其他框架创建单页应用程序的经验,那么其中一些概念可能看起来很熟悉。 例如,React使用类似的状态管理系统Redux。 Vuex和Redux受Flux项目的影响。 这是Facebook提出的架构,旨在简化客户端Web应用程序的构造。 它有助于数据在一个方向上的移动:从动作到调度程序,再到存储,最后到视图。 这种方法允许您将状态与应用程序的其余部分分开,并鼓励同步更新。 您可以从facebook.imtqy.com/flux/docs/overview.html上的官方文档中了解有关Flux的更多信息。

Vuex按照相同的原理工作,有助于可预测和同步地更改状态。 开发人员无需担心使用同步和异步功能更新状态的后果。 想象一下,我们正在与一个服务器API交互,该服务器API以JSON格式返回数据。 如果同时由第三方库修改此数据会怎样? 我们不希望出现不可预测的结果。 Vuex通过消除任何异步更改来帮助避免此类情况。
您可能想知道为什么我们甚至需要Vuex库。 最后,Vue.js允许您将信息传递给组件。 从前面的章节中可以知道,输入参数和用户事件就是为此目的而设计的。 我们甚至可以创建自己的事件总线以进行数据传输和组件间通信。 这种机制的一个例子在图1中给出。 10.1。

这将适合于具有少量组件的小型应用程序。 在这种情况下,您只需要将信息传送给几个收件人即可。 但是,如果应用程序更大,更复杂且分层,该怎么办? 很明显,在大型项目中,要跟踪所有回调函数,输入参数和事件并非易事。

仅在这种情况下,才创建了Vuex库。 它允许您以集中存储库的形式组织与状态有关的工作。 想象一下一个值得考虑使用Vuex的场景。 例如,我们正在制作一个博客,其中包含您可以创建,编辑和删除的文章和评论。 同时,我们有一个管理面板,允许您阻止和添加用户。

让我们看看如何使用Vuex来实现。 在图。 图10.2显示EditBio组件是管理面板的子级。 他需要访问用户信息,以便可以对其进行更新。 与Vuex一起使用,我们可以直接从EditBio组件访问中央存储库,修改数据并保存更改。 这比将信息从Vue.js的根实例传递到Admin组件,然后使用输入参数传递到EditBio更好。 对于我们而言,要跟踪位于不同位置的数据将很困难。

图片

图片

尽管如此,使用Vuex的代价是附加的样板代码和应用程​​序结构的复杂性。 如前所述,最好不要在包含多个组件的简单项目中使用此库。 它的真正潜力体现在状态更为复杂的大型应用程序中。

10.2。 Vuex中的状态和突变


Vuex将整个应用程序的状态存储在单个对象中,该对象也称为单个事实来源。 顾名思义,所有数据都收集在一个地方,而在代码的其他部分则没有重复。
提示

值得注意的是,我们不需要将所有数据存储在Vuex中。 各个组件可能具有自己的本地状态。 在某些情况下,这是可取的。 例如,您的组件具有仅在内部使用的变量。 她必须留在当地。
考虑一个在Vuex中使用状态的简单示例。 我们所有的代码都将放在一个文件中。 稍后,您将学习如何使用Vue-CLI将Vuex添加到项目中。 打开文本编辑器并创建vuex-state.html文件。 我们将在中央存储库中显示一条消息和一个计数器。 结果如图2所示。 10.3。

图片 首先,添加脚本标签以及指向Vue和Vuex的链接。 然后创建HTML标记。 我们将使用标签H1,H2,H3和按钮。 h1标签显示带有在Vue.js.实例中声明的局部变量的标头。 将根据Vuex存储库将欢迎消息和计数器消息作为计算的属性执行。

该按钮元素触发一个增量动作。 将清单10.1中的代码复制到vuex-state.html文件中。

图片

完成HTML标记后,让我们开始创建Vuex存储库。 它将包含所有应用程序数据,包括msg和count属性。

为了更新状态,我们使用了突变。 这类似于其他编程语言中的设置器。 设置器设置该值,该突变更新程序的状态。 在Vuex中,突变必须是同步的。 在我们的示例中,仅在单击按钮时计数器才会增加,因此无需担心异步代码(以后我们将考虑有助于解决异步问题的操作)。

在突变对象内创建一个递增函数,以递增状态。 使用清单10.2中的代码,并将其粘贴到vuex-state.html文件的底部。

图片

因此,我们准备了HTML标记和Vuex存储库。 现在,您可以添加将它们连接的逻辑。 我们希望模板显示味精和计数器值,它们是Vuex状态的一部分。 另外,计数器需要更新。

使用新的数据函数创建Vue.js实例,该实例将返回带有Vuex App文本的本地标头属性。 在计算部分中,添加计算的属性welcome和counter。 第一个将返回store.state.msg,第二个将返回store.state.count。

最后,您需要添加一个称为增量的方法。 Vuex存储库中已经声明了一个变异,但是我们不能直接使用它来更新状态。 为此提供了一个特殊的提交功能。 它告诉Vuex更新存储库,从而保存更改。 表达式store.commit(“增量”)执行该突变。 在清单10.2中创建的代码之后立即插入以下代码段(清单10.3)。

图片

这是一个基于Vuex的功能完备的应用程序! 尝试按按钮-每按一次计数器应增加1。

更新代码,使按下按钮可使计数器递增10。如果仔细观察递增突变,您会注意到它仅接受一个参数,即state。 让我们传递另一个-我们称之为有效负载。 它会通过在Vue.js的根实例中创建的增量方法传递。

将vuex-state.html的内容复制到新的vuex-state-pass.html文件。 以该应用程序为例,我们展示了如何传递参数。

如清单10.4所示,仅需要更新mutation对象和增量方法。 向变异增量添加另一个称为有效负载的参数。 这是state.count将增加的值。 在增量方法中找到对store.commit的调用,然后将10指定为第二个参数。 如下所示更新vuex-state.html文件。

图片

保存vuex-state-pass.html文件,然后在浏览器中打开它。 现在,当按下按钮时,计数器应增加10,而不是1。如果出现问题,请检查浏览器控制台并确保没有错字。

10.3。 吸气剂和动作


在前面的示例中,我们直接从计算出的属性访问商店。 但是,如果我们有几个需要相同访问权限的组件怎么办? 假设我们要以大写字母显示欢迎消息。 在这种情况下,吸气剂将为我们提供帮助。

吸气剂是Vuex的一部分。 它们允许您对所有组件中的状态实施统一访问。 让我们以10.2节中的示例为例,我们使用getter代替通过计算的属性直接访问存储库。 另外,我们使msg属性的getter将其所有字母都转换为大写。

将vuex-state-pass.html文件的内容复制到vuex-state-getter-action.html。 为了简化任务,请保留HTML代码不变。 最后,您应该得到类似于无花果的东西。 10.4。

图片 如您所见,Hello World消息现在以文字显示。 按“按我”按钮以与上一个示例相同的方式使计数器递增。

在标记下方的新vuex-state-getter-action.html文件中找到Vuex.Store构造 图片 在称为吸气剂的突变后添加一个新对象。 在此对象内创建msg和count方法,如清单10.5所示。 两种方法都接受相同的状态参数。

信息获取器将返回state.msg.toUppercase()。 因此,该消息始终以大写形式显示。 在getter中,我们将返回state.count。 在突变下方添加吸气剂后,vuex-state-getter-action.html文件应如下所示。

图片

动作是Vuex的另一个组成部分。 我之前提到过,突变必须是同步的。 但是,如果我们使用异步代码怎么办? 如何使异步调用能够更改状态? Vuex的操作将帮助我们实现这一目标。
想象一下,该应用程序正在访问服务器并等待响应。 这是异步操作的示例。 不幸的是,突变是异步的,因此我们不能在这里使用它们。 相反,请基于Vuex操作添加异步操作。

要创建延迟,请使用setTimeout函数。 打开vuex-state-getter-action.html文件,并在获取方法之后立即将action对象添加到其中。 在该对象内部,放置增量操作,该操作采用上下文和有效负载参数。 使用上下文,我们将保存更改。 将context.commit操作放在setTimeout中。 这样,我们可以模拟服务器上的延迟。 我们还可以将有效负载参数传递给context.commit,然后进入突变。 根据清单10.6更新代码。

更新Vuex.Store之后,您可以进入Vue.js的根实例。 与以前一样,calculated属性将不会直接访问存储,而是使用getter。 我们还在修改增量方法。 要访问我们之前创建的新Vuex属性,它将使用调用store.dispatch('increment',10)。

图片

调度调用的第一个参数是操作的名称,第二个参数始终包含传递给该操作的其他数据。
提示

附加数据可以是常规变量,甚至可以是对象。
如清单10.7所示,更新vuex-state-getter-action.html文件中的Vue.js实例。
图片

下载应用程序,然后按几次按钮。 您应该注意到有一个延迟,但是每次按下后计数器都会增加10。

10.4。 使用Vue-CLI在宠物商店项目中使用Vuex


让我们回到我们正在从事的宠物商店项目。 如果您还没有忘记的话,我们定会添加动画和转场。 现在,我们集成了我们先前遇到的Vuex库。

我们将货物数据转移到仓库。 如您在前几章中所记得的,数据是在Main组件内创建的钩子中初始化的。 现在,此挂钩应生成一个新事件,该事件将初始化Vuex存储库。 我们还将添加计算出的属性产品,该产品将使用getter检索产品(我们将在以后创建它)。 最终结果将如图2所示。 10.5。

图片

10.4.1。 使用Vue-CLI安装Vuex


首先,安装Vuex! 这是一个简单的过程。 准备我们在第8章中研究过的宠物商店的最新版本。您还可以在GitHub.github.com/ErikCH/VuejsInActionCode上下载本章的所有代码。

打开一个终端窗口,然后转到项目的根目录。 要安装最新版本的Vuex,请运行以下命令:

$ npm install vuex 

并将有关它的记录保存在宠物商店的package.json文件中。

现在,您需要将存储添加到main.js文件中,该文件位于src文件夹中。 存储库本身尚不存在,但是我们还是要导入它。 通常它位于src / store / store.js文件中,但是您可以选择其他路径-所有开发人员都有自己的偏好。 让我们谈谈普遍接受的选择。 在本章的后面,我们将讨论使用模块的替代目录结构。

您需要在路由器下方的Vue.js的根实例中添加存储,如清单10.8所示。 顺便说一下,我们使用ES6标准,因此store:store可以缩短为store。

图片

将存储连接到根实例后,我们可以从应用程序的任何部分访问它。 创建src / store / store.js文件。 在其中,我们将放置Vuex存储库,其中包含有关宠物店提供的产品的信息。 在顶部,添加两个import语句,一个用于Vue和Vuex。 然后指定Vue.use(Vuex)将所有内容放在一起。

我们从./store/store将存储库导入到main.js文件中。 现在,您需要在store.js中导出store对象。 如清单10.9所示,我们导出了一个等于Vuex.Store的const存储值。

首先,添加具有状态和突变的对象。 该状态将包含一个称为产品的空对象。 很快,我们将使用initStore方法填充它。 该突变称为SET_STORE,它将把转移的商品分配给state.products属性。 将以下清单中的代码粘贴到我们刚刚创建的src / store / store.js文件中。

图片

我们需要在存储库中创建一个action和getter。 吸气剂将返回产品对象。 动作有点复杂。 您应该将创建的挂钩(使用Axios读取static / products.json文件)转移到Vuex内部的action对象。

前面我提到过,突变必须是同步的,只有Vuex内部的动作才能接受异步代码。 要解决此限制,请将Axios代码放入Vuex操作中。

在store.js文件中创建一个action对象,并向其添加initStore方法。 将组件/ Main.vue文件中创建的钩子的内容复制到此方法中。 与其将response.data.products分配给products对象,我们使用commit函数来调用变异。 将response.data.products作为参数传递给SET_STORE。 产生的代码应如下所示(清单10.10)。

图片

我们差不多完成了,只需要更新Main.vue文件并将商品从本地产品对象转移到Vuex存储库即可。 打开src / components / Main.vue文件并找到数据功能。 删除以下产品:{}。 我们将从商店返回的计算属性中访问商品。

在Main.vue中找到计算出的属性cartItemCount和sortedProducts,它们应该在方法部分之后。 添加products属性,并使其返回同名的getter。

我们将存储库连接到main.js文件中的Vue.js根实例,因此不再需要导入它。 另外,在使用Vue-CLI时,始终以这种形式提供存储。 不要忘记$符号,否则将导致错误。 添加计算产品属性,如清单10.11所示。

图片

查找在其中初始化了product对象的创建的挂钩,然后删除其内容。 而是在Vuex存储库中插入我们先前创建的initStore操作调用。 要调用动作,请使用上一个示例中的dispatch函数。 清单10.12显示了更新Main.vue文件后创建的钩子的外观。

图片

那应该足够了。 在终端中运行npm run dev命令,屏幕上将出现一个包含pet store应用程序的窗口。 尝试将货物放在篮子里,并确保一切正常。 如果出现问题,请在控制台中查找错误。 在src / store / store.js文件中,您可能会不小心键入Vuex.Store,而不是Vuex.store。 记住这一点!

10.5。 辅助方法Vuex


Vuex提供了方便的帮助程序方法,这些方法使代码更加简洁,并且无需添加相同的getter,setter,mutation和action。 有关Vuex帮助程序方法的完整列表,请参阅官方指南,网址为vuex.vuejs.org/guide/core-concepts.html。 让我们看看它们是如何工作的。

您应该知道的主要辅助方法称为mapGetters。 它用于将所有可用的吸气剂添加到计算的部分,而不需要列出每个吸气剂。 但是在使用它之前,您需要将其导入组件内部。 再次返回宠物商店并添加mapGetters方法。

打开src / components / Main.vue文件并找到脚本标签。 在此标签内的某个位置,应导入Header组件。 导入后立即连接mapGetters,如清单10.13所示。

图片

现在,您需要更新计算出的属性。 在计算出的部分中找到product函数,然后将mapGetters对象插入其位置。

mapGetters是一个唯一的对象,为了使其正常运行,有必要使用ES6中的散布运算符-在需要任何自变量(零个或多个)的情况下,它会扩展表达式。 您可以在developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Spread_syntax的MDN文档中了解有关此语法的更多信息。

mapGetters将确保所有吸气剂都作为计算属性添加。 与为每个getter编写单独的计算属性相比,这是一种更简单,更优雅的方法。 所有的获取方法都在mapGetters数组中列出。 将此辅助方法添加到Main.vue文件中(清单10.14)。

图片

运行npm run dev命令后,宠物商店应该像以前一样工作。 到目前为止,mapGetters帮助器方法看起来不是很有用,但是我们添加的吸气剂越多,节省的时间就越多。

您还应该知道另外三种帮助程序方法:mapState,mapMutations和mapActions。 它们都以类似的方式工作,从而减少了您必须手动编写的样板代码量。

想象一下,您的存储库包含几段数据,并且直接从组件进行状态访问,而无需使用任何获取器。 在这种情况下,可以在计算部分内使用mapState方法(清单10.15)。

图片

现在,假设您需要在组件中使用多个突变。 为了简化此过程,请使用mapMutations帮助程序方法(清单10.16),与mapState和mapGetters一样。 下一个mut1将此this.mut1()绑定到此$ Store.commit('mut1')。

图片

最后,考虑mapActions辅助方法。 它允许您将Vuex操作添加到应用程序,而无需在每种情况下都需要使用分派调用来创建方法。 回到前面的示例,假设应用程序包含一些异步操作。 由于不使用突变,因此我们必须采取行动。 在Vuex中创建它们之后,您需要在组件的methods对象中访问它们。 可以使用mapActions解决此问题。 act1将this.act1()绑定到$ .store.dispatch('act1'),如代码清单10.17所示。

图片

最后,考虑mapActions辅助方法。 它允许您将Vuex操作添加到应用程序,而无需在每种情况下都需要使用分派调用来创建方法。 回到前面的示例,假设应用程序包含一些异步操作。 由于不使用突变,因此我们必须采取行动。 在Vuex中创建它们之后,您需要在组件的methods对象中访问它们。 可以使用mapActions解决此问题。 act1将this.act1()绑定到$ .store.dispatch('act1'),如代码清单10.17所示。

图片

随着应用程序的增长,这些辅助方法将变得越来越有用,从而减少了需要编写的代码量。 请记住,您需要仔细考虑存储库中的属性名称,因为帮助程序方法允许您在组件中访问它们。

10.6。 模块简介


在本章开始时,我们在src / store目录中创建了store.js文件。 对于小型项目,此方法非常合适。 但是,如果我们要处理更大的应用程序该怎么办? store.js文件将快速增长,并且很难跟踪其中发生的一切。
为了解决这个问题,Vuex提供了模块的概念。 模块使您可以将存储分为几个较小的部分。 每个模块都有自己的状态,变异,动作和获取器,您甚至可以将它们嵌套在一起。

我们使用模块重写了宠物店。 store.js文件将保留在原处,但是在它旁边,您应该创建modules文件夹并将products.js文件放置在此处。 目录结构应类似于图1。 10.6。

图片 在products.js中,您需要创建四个对象:状态,获取器,操作和突变。 它们每个的内容都应该从store.js文件中复制。

打开src / store / store.js文件,然后开始从中复制代码。 完成后,products.js文件应如下所示(清单10.18)。

现在,我们需要导出添加到product.js文件中的所有代码。 这会将其导入到store.js中。 在文件底部,添加表达式export default。 这是ES6格式的导出指令,可让您从其他文件中导入此代码(清单10.19)。

store.js文件应该被更新。 向其中添加一个模块对象,您可以在其中列出所有新模块。 记住要导入我们之前创建的模块/产品文件。

图片

我们的示例仅包含一个模块,因此请立即将其添加到modules对象。 您还需要从Vuex.Store中删除所有不必要的内容,如清单10.20所示。

图片

通过导入模块,我们完成了重构过程。 刷新页面后,该应用程序应完全像以前一样工作。
Vuex中的命名空间

在某些大型项目中,模块化会引起某些问题。 当添加新模块时,动作名称,获取方法,变异和状态属性可能会产生冲突。 例如,您可能不小心将相同的名称分配给了不同文件中的两个getter。 并且,由于所有内容都在Vuex中的全局全局命名空间中,因此控制台中将发生重复的键错误。
为避免此问题,请将每个模块放在单独的名称空间中。 为此,只需在Vuex.store顶部指定命名空间:true。 在vuex.vuejs.org/en/guide/modules.html上的官方Vuex文档中了解有关此功能的更多信息。
»这本书的更多信息可以在出版商的网站上找到
» 目录
» 摘录

小贩优惠券可享受25%的折扣-Vue.js

支付纸质版本的书后,将通过电子邮件发送该书的电子版本。

Source: https://habr.com/ru/post/zh-CN448304/


All Articles