前言
在你学习如何制作vue.js应用之前,首先,让我们谈谈你应该知道的一些事情。
在写这本书时,我反复听到vue.js官方教程是最好的学习资源。虽然官方指南很好,我强烈建议你把它们作为额外辅助材料,但是,他们没有涵盖所有的东西,他们也不是完美的。在我写这本书的时候,我决定超越官方指南所涵盖的范围。我让这些例子更容易理解和联系,这样你就可以更容易地将这些概念应用到你自己的项目中。当我认为某个主题超出了本书的范围,或者不够重要时,我添加了一个参考,您可以在官方指南中了解更多。
这本书有几种不同的用法。你可以从头到尾读。在这种情况下,你将得到vue.js必须提供的所有内容。或者你可以用这本书作为参考手册来查找任何你需要更多信息的概念。任何一种方式都可以接受。
在本书后面我们将过渡到使用build创作vue.js的应用程序。别担心,我已经在附录A中介绍了如何开始使用vue.js的构造系统Vue-CLI。Vue-Cli的一个最重要的好处是它可以帮助我们创建更复杂的vue.js应用程序,而不必担心构建或传输我们的代码。
在整本书中,我们将创建一个vue.js宠物商店应用程序。某些章节比其他章节更多地使用宠物商店的例子。我这样做是有目的的,所以你可以很容易地学习一个概念,而不必学习如何与宠物商店的应用程序工作。但是那些喜欢用实际应用程序学习的人仍然有这个选择。观众历史主题学习路径提供和交易亮点设置支持注销
读者
这本书是为任何有兴趣学习的人准备的vue.js并且拥有JavaScript、HTML和CSS的经验。我不希望您对此有太多的了解,但是了解一些基础知识,比如数组、变量、循环和HTML标记会有所帮助。至于CSS,我们将使用bootstrap3,一个CSS库。但是,您不需要了解任何有关引导的知识就可以跟随示例一起使用。它只是用来帮助造型的。
在本书的早期,我介绍了使用ECMAScript 2015(也称为ES6)的示例代码。在你开始读这本书之前把它看一遍是个好主意。在大多数情况下,我只使用了一些ES6特性,比如箭头函数和ES6导入。我会在书中警告你当我们做这个转变。
这本书分为三个部分,每一部分都建立在前一部分的基础上。第一部分主要是为了了解vue.js. 在第一章和第二章中,我们将创建第一个vue.js应用程序。我们来看看vue.js实例以及它与我们的应用程序的关系。在第2部分第3-9章中,我们将更仔细地研究视图和视图模型。在本节中,我们将深入了解vue.js. 第一部分更像是开胃菜vue.js,第二部分是主菜。您将学习如何创建vue.js应用程序。我们将从学习反应模型开始,并创建一个宠物商店应用程序,我们将在本书的其余部分使用它。我们将添加表单和输入,以及如何使用vue.js的强大指令,然后查看条件、循环和窗体。第六章和第七章非常重要。我们将学习如何打破僵局vue.js使用组件将应用程序分为几个逻辑部分,我们将首先了解您需要创建的构建工具vue.js应用程序。第7章还介绍了路由。在前面的章节中,我们使用简单的条件来导航我们的应用程序。通过添加路由,我们可以在应用程序中适当地移动,并在路由之间传递信息。第8章向您介绍可以使用vue.js. 这些特性已经融入到语言中,是您应该检查的好特性。
在第9章中,我们将学习如何使用mixin和自定义指令来轻松地扩展Vue,而无需重复。第3部分是关于建模数据、使用API和测试的。在第10章和第11章中,我们首先深入研究Vue的状态管理系统Vuex。然后,我们将研究如何开始与后端服务器通信,并将了解有关的更多信息文本.js,服务器端呈现的框架。第12章专门介绍了测试。在任何专业环境中,您都需要了解测试,我们将介绍您必须了解的要点。
源代码
这本书的源代码可以从出版商的网站上下载(www.manning.com/books/vuejsinaction)和我的个人GitHub存储库(https://github.com/ErikCH/VuejsInActionCode). 您还可以在附录A中找到有关下载代码和设置编程环境的更多说明。
在线资源
正如我前面提到的,在线资源vue.js官方指南是很好的使用作为参考,而你在工作的例子在书中。你可以在https://vuejs.org/v2/guide/。它们不断更新。
在https://github.com/vuejs/awesomevue有一个列表与Vue.js相关的好东西. 在这儿, 你可以发现Vue.js 广播, 额外的Vue.js资源, 第三方的类库, 甚至是使用Vue.js的公司. 我强烈建议你看一下。
- MVC和MVVM设计模式
- 这些模式定义一个反应式应用程序
- 描述Vue生命周期
- 评估vue.js
- 视图可能包含JavaScript,在输入或提交之前验证邮政编码。
- 当模型创建一个地址对象以保存传入数据时,该模型可能会验证邮政编码。
- ZIP代码字段上的数据库约束可能意味着模型也在强制执行业务逻辑,尽管这可能被认为是一种不好的做法。
- 观察应用状态的变化
- 在整个应用程序中传播更改通知
- 根据状态更改自动渲染视图
- 为用户交互提供及时反馈
反应式web应用程序通过采用MVVM设计原则来实现这些目标,MVVM设计原则使用异步技术来避免阻塞持续的交互,并在可能的情况下使用函数式编程习惯用法。
1窗体输入以收集绑定到runCalc函数的x和y
2显示x和y的结果
3显示了创建计算实例的构造函数
4显示了为calc实例创建值的构造函数
5初始化计算组件
6显示事件处理程序
7在keyup上设置事件侦听器
这是一个使用ES5JavaScript的计算器(我们将在本书后面使用更现代的JavaScriptES6/2015版本)。我们使用一个立即调用的函数表达式来启动JavaScript。构造函数用于保存值,handleCalcEvent事件处理程序在任何keyup上激发。
1显示了我们应用程序的DOM锚
2显示应用程序的表单输入
3个结果将显示在这个范围内。
4列出添加vue.js库
5初始化应用程序
6连接到DOM
7显示添加到应用程序的变量
8这里使用计算属性进行计算。
1.1.6. JavaScript与Vue的比较
这两种计算器实现的代码在很大程度上是不同的。图1.3所示的每个示例都可以在本章附带的存储库中找到,因此您可以运行每个示例并比较它们的操作方式。
图1.3 使用vanilla JavaScript(左侧)和Vue(右侧)编写的反应式计算器的并排比较。
为什么现在都不用jquery了?
Element.querySelector():https://developer.mozilla.org/zh-CN/docs/Web/API/Element/querySelector
两个应用程序之间的关键区别在于如何触发对最终计算的更新以及结果如何返回到页面。在我们的Vue示例中,单个绑定v模型负责页面上的所有更新和计算。当我们用新的Vue({。。。}),Vue检查JavaScript代码和HTML标记,然后创建应用程序运行所需的所有数据和事件绑定。
由于完全由web技术构建,单个Vue实例完全存在于web浏览器中。关键的是,这意味着我们不依赖于基于服务器的页面重新加载来更新视图、执行业务逻辑或任何其他属于视图或视图模型域的任务。让我们考虑一下表单提交的例子。
与客户端MVC架构相比,最显著的变化可能是浏览器页面很少需要在用户的整个会话期间重新加载。因为视图、视图模型和数据绑定都是用HTML和JavaScript实现的,所以我们的应用程序可以异步地将任务委托给模型,让用户可以继续执行其他任务。当从模型返回新数据时,Vue建立的绑定将触发视图中需要发生的任何更新
可以说,通过创建和维护我们创建的视图和视图模型中的数据之间的绑定来促进用户交互是Vue的主要角色。在这种能力下,正如我们将在第一个应用程序中看到的,Vue为任何反应式web应用程序提供了坚实的基础。
1.2. 为什么选择VUE.JS?
当开始一个新项目时,有很多决定要做。其中最重要的是应该使用的框架或库。如果你是一个代理甚至是一个单独的开发人员,为工作选择正确的工具是非常重要的。幸运的是,虚拟用户.js是多才多艺的,可以处理许多不同的情况。
以下是您作为单独的开发人员或代理启动新项目时可能遇到的几个最常见的问题,以及Vue如何帮助解决这些问题的描述,这些问题可以是直接解决的,也可以是响应式web应用程序更大发展的一部分。
- 我们的团队不擅长使用web框架。在项目中使用Vue的最大优点之一是它不需要任何专业知识。每一个Vue应用程序都是用HTML、CSS和JavaScript构建的,这些工具让你从一开始就有效率。即使是没有开发任何类型前端经验的团队,也会在MVVM模式中找到一个舒适的立足点,因为他们熟悉其他环境中的MVC。
- 我们有现有的工作,我们想继续使用。别担心,没有必要废弃你精心制作的CSS或者你构建的很酷的旋转木马。无论您是将Vue放到一个具有许多依赖项的现有项目中,还是启动一个新项目并希望利用您已经熟悉的其他库,Vue都不会妨碍您。您可以继续使用Bootstrap或Bulma之类的工具作为CSS框架,保留jQuery或主干组件,或者合并您首选的库以进行HTTP请求、处理承诺或其他扩展功能。
- 我们需要快速制作原型并评估用户的反应。正如我们在第一个Vue应用程序中所看到的,开始使用Vue构建所需做的就是包含虚拟用户.js在任何独立网页中。不需要复杂的构建工具!在开始开发的一两周内,就可以在用户面前获得一个原型,这样您就可以尽早收集反馈并经常迭代。
- 我们的产品几乎只用于移动设备。缩小和压缩虚拟用户.js文件的重量约为24KB,对于前端框架来说非常紧凑。该库可以通过蜂窝网络轻松传送。VUE2的新功能是服务器端渲染(SSR)。这样的策略意味着应用程序的初始负载可以是最小的,只允许您根据需要引入新的视图和资源。将SSR与组件的高效缓存相结合,可以进一步降低带宽消耗
- 我们的产品具有独特的定制功能。Vue应用程序从一开始就考虑到模块化和可扩展性,使用可重用组件。Vue还支持通过继承扩展组件,将功能与mixins结合,并通过插件和自定义指令扩展Vue的功能。
- 我们有一个庞大的用户群和性能是一个问题。最近为可靠性、性能和速度而重新编写的Vue现在使用虚拟DOM。这意味着Vue首先对未连接到浏览器的DOM表示执行操作,然后将这些更改“复制”到我们看到的视图中。因此,Vue通常优于其他前端库。因为一般化测试通常过于抽象,所以我总是鼓励客户选择几个典型的用例和一些极端的用例,开发一个测试场景,并自己度量结果。您可以进一步了解虚拟DOM及其与竞争对手的比较https://vuejs.org/v2/guide/comparison.html。
- 我们有一个现有的构建、测试和/或部署过程。在本书的后面几章中,我们将深入探讨这些主题,但收获是Vue很容易集成到许多最流行的构建(Webpack、Browserify等)和测试(Karma、Jasmine等)框架中。在许多情况下,如果已经为现有框架编写了单元测试,那么单元测试可以直接移植。如果您刚开始使用这些工具,Vue会为您提供集成这些工具的项目模板。用最简单的术语来说,将Vue添加到现有项目中并使之适应是很容易的。
- 如果我们在应用之后需要帮助,我们该怎么办?Vue的两个不可估量的好处是它的社区和支持生态系统。Vue在在线文档和代码本身中都有很好的文档记录,核心团队是积极的和响应的。也许更重要的是,与Vue合作的开发人员社区同样强大。诸如Gitter和Vue论坛之类的资源中充满了有用的人,而且几乎每天都有越来越多的插件、集成和库扩展将流行代码带到平台上
在我自己的项目中问了很多这样的问题之后,我现在几乎在我所有的项目中都推荐Vue。当你在这本书中对自己对Vue的掌握充满信心时,我希望你能在下一个项目中为Vue辩护。
1.3. 未来的想法
仅在这一章的导论中,我们就讲了很多内容。如果您是web应用程序开发的新手,这可能是您第一次接触MVVM体系结构或反应式编程,但我们已经看到,构建反应式应用程序并不像行话所说的那样令人生畏。
也许本章最大的收获不是关于Vue本身,而是如何更容易使用和编写反应式应用程序。我们有更少的样板接口代码要编写,这也很好。不必编写所有用户交互的脚本,我们就可以专注于如何建模数据和设计界面。将它们连接起来是Vue毫不费力的事情。
如果你像我,那么你已经在考虑各种各样的方法,你可以使我们的朴素的应用程序更好。这是一件好事,你应该绝对地尝试和玩代码。以下是我在看应用程序时所想的一些事情:
- 我们如何消除在这么多地方重复文本字符串的需要?
- 当用户关注某个输入时,我们能清除默认输入吗?如果他们将字段留空,如何恢复它?
- 有没有办法避免对每个输入进行手工编码?
在第2部分中,我们将找到所有这些问题的答案,以及更多的答案。Vue的设计是与我们一起成长,就像开发人员一样,与我们的代码一样,因此我们将始终确保查看不同的策略,比较它们的优缺点,并学习如何决定哪种策略是特定情况下的最佳实践。
总结
模型、视图和控制器如何工作以及它们如何绑定到vue.js.
怎样vue.js可以节省创建应用程序时的时间。
你为什么要考虑vue.js为你的下一个项目。
如果您尝试了清单1.2中的简单计算器示例,从技术上讲,这将是您的第二个Vue应用程序。你已经是个老兵了!
在开始之前,请下载浏览器的vue-devtools插件。你可以在附录A中找到更多关于如何下载这个插件的信息。
2.1.1 根视图实例
无论大小,每个Vue应用程序的核心都是根Vue实例,简称Vue实例。通过调用Vue构造函数new Vue()创建根Vue实例。构造函数通过编译应用程序的HTML模板、初始化任何实例数据以及创建使应用程序具有交互性的数据和事件绑定来引导应用程序。
Vue构造函数接受一个单个的JavaScript对象,称为options对象,new Vue({/* options放在这儿*/})。我们的工作是用Vue构造函数引导我们的应用程序所需的一切填充该对象,但首先我们只关注一个选项,el选项。
el选项由Vue用来指定一个DOM元素(因此是el),Vue将在其中装载我们的应用程序。Vue将在HTML中找到相应的DOM元素,并将其用作应用程序的装入点。
这段代码是我们webstore应用程序的开始。为了便于理解,我将每个代码列表都包含在自己的文件中,您可以在本章下载这些文件。但要运行应用程序,需要将每个文件中的每个代码片段组合成一个单独的代码段index.html文件。是的,那个index.html当我们读这本书的时候,文件会变得相当大,这很正常。在以后的章节中,我们将讨论如何将应用程序拆分为单独的文件。
如果您想查看本章中完整的应用,请查看index.html代码包含在chapter02文件夹中的文件。(如果您还没有下载本章附带的代码,请在附录A中了解如何以及在何处获得它。)让我们创建第一个Vue应用程序。
1 列出了的CDN版本vue.js
2 我们的内部应用程序.css样式表以及引导样式表
3 Vue将装入我们的应用程序的元素
4 Vue构造函数
5 列出了一个CSS选择器用于定位DOM安装点
标记包含一个带有CSS ID选择器#app的div元素。Vue使用该值来定位我们的div并将应用程序装载到它。此选择器匹配CSS使用的相同语法(例如#id、.class)。
在本书中,我们将使用bootstrap3进行所有的布局和设计。这非常有效,有助于保持注意力集中在vue.js. 在撰写本文的时候,bootstrap4最近发布了,但是因为这本书的重点不是设计,所以我决定把bootstrap3留在里面。这些例子适用于bootstrap4;,但是如果您确实要切换,您可能需要将几个类换成较新的bootstrap4类。记住这一点。
如果我们提供的CSS选择器解析为多个DOM元素,那么Vue将把应用程序装载到与选择器匹配的第一个元素。如果我们有一个包含三个div元素的HTML文档,并将Vue构造函数作为新的Vue({el:'div'})调用,那么Vue将在三个div元素中的第一个div元素装入应用程序。
如果需要在一个页面上运行多个Vue实例,可以使用唯一的选择器将它们装载到不同的DOM元素。这似乎是一种奇怪的做法,但是如果您使用Vue来构建小组件,例如图像转盘或webform,那么很容易看到如何在一个页面上运行多个根Vue实例。
2.1.2 确保我们的应用程序正在运行
让我们转到Chrome,打开清单2.1中为第一个Vue应用程序创建的文件,尽管它还不能呈现在主浏览器窗口中看到的任何内容。(毕竟,没有可见的HTML!)
一旦页面加载,打开JavaScript控制台如果它还没有打开,希望你会看到...<drum roll>.....什么也没有(或者可能是关于下载vuedevtools的注释,如果您还没有这样做,或者是在开发模式下运行vue的注释)。图2.2显示了控制台的外观。
即使到目前为止我们的应用程序很简单,但当我们在Chrome中加载文件时仍然会遇到麻烦。当事情没有按计划进行时,有两个常见的问题需要注意:
- uncaughtsyntaxerror:意外的标识符几乎总是指示JavaScript代码中的输入错误,并且通常可以跟踪到缺少的逗号或大括号。您可以单击错误右侧显示的文件名和行号以跳转到相应的代码。请记住,你可能需要搜索几行或上下找到令人不快的打字错误。
- [Vue warn]:未定义属性或方法“propertyname”。让您知道在创建实例时options对象中没有定义某些内容。检查options对象中是否存在该属性或方法,如果存在,请检查其名称中是否有拼写错误。还要检查标记中绑定的名称拼写是否正确。
最初几次跟踪错误可能会让人沮丧,但在解决了一些错误之后,这个过程会变得更自然。
如果您遇到了一些您无法理解的问题,或者您发现了一个特别严重的错误,您可以访问Vue论坛的帮助部分https://forum.vuejs.org/c/help或者在Vue Gitter聊天中寻求帮助https://gitter.im/vuejs/vue。
在Vue完成应用程序的初始化和装载之后,它返回对根Vue实例的引用,我们将其存储在webstore变量中。我们可以使用该变量在JavaScript控制台中检查我们的应用程序。在继续之前,让我们现在使用它来确保我们的应用程序处于活动状态。
在控制台打开的情况下,在提示符处输入webstore。结果是一个Vue对象,我们可以在控制台中进一步检查它。现在,单击disclosure triangles()展开对象并查看根Vue实例的属性,如图2.3所示。
图2.3:使用webstore变量显示Vue实例的表示形式并探索其属性。
您可能需要滚动一点,但是您应该能够找到作为应用程序options对象的一部分指定的el属性。在以后的章节中,我们将使用控制台访问实例,以便在应用程序运行时调试、操作数据和触发应用程序中的行为,这样我们就可以验证它的行为是否符合预期。我们还可以使用vuedevtools在应用程序运行时查看其内部。(同样,如果您还没有安装vuedevtools,请访问附录A了解如何安装它。)让我们看看它与使用JavaScript控制台的比较。图2.4显示了vuedevtools的不同部分。
当您在树状视图中选择一个实例时,如图2.5所示,vuedevtools将实例的引用分配给$vm0变量。我们可以像使用webstore变量一样使用$vm0。尝试在JavaScript控制台中使用$vm0,看看是否可以检查根Vue实例。
为什么我们需要不止一个参考呢?
使用多种方法访问同一实例可能显得多余,但同时使用这两种方法会有所帮助。
当我们将根Vue实例分配给全局变量webstore时,我们为自己提供了一种在页面上的其他JavaScript代码中引用应用程序的方法。这样做允许我们与其他库、框架或我们自己的代码集成,这些代码可能需要引用回我们的应用程序。
分配给$vm0变量的Vue实例反映了在Vuedevtools中所做的当前选择。当一个应用程序由数百个,甚至数千个实例组成时,以声明方式分配每个实例是不实际的,因此在检查和调试这样一个复杂的应用程序时,访问以编程方式创建的特定实例的方法是必不可少的。
1将头元素添加到div。
2显示sitename属性的数据绑定
3将数据对象添加到Vue选项
4显示了我们在标头中绑定到的sitename属性
我们在传递到Vue构造函数的选项中添加了一个数据对象。该数据对象包含一个属性sitename,它包含我们的webstore的名称。
我们的站点名称需要一个home,因此我们还向应用程序根div元素内的标记添加了一个header元素。在标题元素<h1>上,我们使用数据绑定元素指令vtext=“sitename”。
vtext指令打印它引用的属性的字符串表示形式。在这种情况下,一旦我们的应用程序启动并运行,我们应该看到一个带有文本的标题“Vue.js Pet Depot”展示在里面。
如果需要在较大字符串的中间显示属性值,可以使用Mustache语法{{property}}绑定到属性。要在句子中包含webstore的名称,您可以编写<p>欢迎使用{{sitename}}</p>。
Vue只借用{{。。。}}文本插值的Mustache语法,而不是整个Mustache规范。但是如果你想知道它是从哪里来的,请访问https://mustache.github.io/mustache.5.html。
数据绑定就绪后,让我们看看新的头在浏览器中的外观。
v-text的用法:https://blog.csdn.net/yycnf/article/details/108310244
vue标签大全:https://blog.csdn.net/xxtnt/article/details/88358965
2.1.4. 检查在Vue中的属性
当您在Chrome中重新加载应用程序时,您应该看到标题自豪地显示了sitename属性的值,如图2.6所示。标题的视觉外观由第02章/assets/css中的样式表提供/应用程序.css. 我们将使用样式表和引导程序来设计应用程序。如果您想修改头的外观,请打开该文件并找到由头h1定义的样式。
在初始化应用程序时,Vue会自动为数据对象的每个属性创建getter和setter函数。这使我们能够检索实例的任何属性的当前值,或为其设置新值,而无需编写任何其他代码。要查看这些函数的运行情况,让我们首先使用getter打印sitename属性的值。
如图2.7所示,sitename属性的getter和setter函数在应用程序实例的根级别公开。它允许我们从JavaScript控制台或与应用程序交互的任何其他JavaScript访问属性。
每个阶段都建立在上一阶段的基础上,以创建Vue生命周期。您可能想知道虚拟DOM是什么,以及呈现函数是如何工作的。虚拟DOM是表示DOM的轻量级抽象。它模仿浏览器通常访问的DOM树。Vue可以比浏览器特定的DOM更快地更新虚拟DOM。渲染函数是Vue向用户显示信息的方式。有关Vue实例和生命周期挂钩的更多信息,请查看官方指南https://vuejs.org/v2/guide/instance.html。
2.2.1. 添加生命周期挂钩
为了查看应用程序实例何时经过生命周期的不同阶段,我们可以为Vue的生命周期挂钩编写回调函数。让我们更新主应用程序文件中的代码(index.html)如清单2.3所示。
钩子是一个函数,它可以“钩住”Vue库代码的一部分。每当Vue在执行过程中到达代码的那一部分时,它就会调用您定义的函数,或者在无事可做的情况下继续执行。
var APP_LOG_LIFECYCLE_EVENTS = true; //#A var webstore = new Vue({ el: "#app", data: { sitename: "Vue.js Pet Depot", }, beforeCreate: function() { //#B if (APP_LOG_LIFECYCLE_EVENTS) { //#B console.log("beforeCreate"); //#B } //#B }, //#B created: function() { //#C if (APP_LOG_LIFECYCLE_EVENTS) { //#C console.log("created"); //#C } //#C }, //#C beforeMount: function() { //#D if (APP_LOG_LIFECYCLE_EVENTS) { //#D console.log("beforeMount"); //#D } //#D }, //#D mounted: function() { //#E if (APP_LOG_LIFECYCLE_EVENTS) { //#E console.log("mounted"); //#E } //#E }, //#E beforeUpdate: function() { //#F if (APP_LOG_LIFECYCLE_EVENTS) { //#F console.log("beforeUpdate"); //#F } //#F }, //#F updated: function() { //#G if (APP_LOG_LIFECYCLE_EVENTS) { //#G console.log("updated"); //#G } //#G }, //#G beforeDestroy: function() { //#H if (APP_LOG_LIFECYCLE_EVENTS) { //#H console.log("beforeDestroy "); //#H } //#H }, //#H destroyed: function() { //#I if (APP_LOG_LIFECYCLE_EVENTS) { //#I console.log("destroyed"); //#I } //#I } //#I });
1显示用于启用或禁用回调的变量
2记录beforeCreate事件
3记录创建的事件
4记录beforeMount事件
5记录挂载事件
6记录beforeUpdate事件
7记录更新的事件
8记录beforeDestroy事件
9记录销毁事件
在清单2.3中您会注意到的第一件事是,我们定义了一个变量APP_log_LIFECYCLE_EVENTS,可以用来启用或禁用生命周期事件的日志记录。我们在Vue实例外部定义变量,以便根实例或稍后编写的任何子组件全局使用它。另外,如果我们在应用程序实例中定义了它,那么它在beforeCreate回调中就不可用了,因为它还没有被创建!
代码的其余部分定义了在遇到每个生命周期事件时记录这些事件的函数。让我们重温一下对sitename属性的控制台探索,看看Vue生命周期中发生了什么。
2.2.2. 探索生命周期代码
如果您在Chrome中打开控制台并重新加载应用程序,您应该立即看到几个回调的输出,如图2.10所示。
正如您所料,在Vue创建和装载应用程序时,前四个生命周期挂钩会被触发。为了测试其他钩子,我们需要与控制台进行一些交互。首先,让我们通过为站点设置一个新名称来触发更新回调。图2.11显示了如何做到这一点。
1我们产品数据的对象
2产品属性是产品对象的属性。
将产品对象添加到数据选项相对简单:
- id属性用于唯一标识产品。如果我们添加更多的产品,这个属性将增加。
- 尽管title和description属性都是字符串,但是描述包含HTML标记。当我们开始在产品标记中显示这些值时,我们将看看这意味着什么。
- price属性将产品的成本表示为整数。这简化了我们稍后要做的计算,并且这种格式避免了在数据库中将值存储为浮点数或字符串时可能发生的破坏性类型转换。
- image属性提供产品主映像文件的路径。我们将反复讨论这一点,所以如果看到这里的硬编码路径让你紧张,放松呼吸,因为我们将探索更好的选择。
有了我们的数据,我们就可以快速查看了。
2.3.2. 标记产品视图
现在我们可以集中精力将产品标记添加到HTML中。在header元素下面,我们将添加一个main元素,作为应用程序内容的主容器。主要元素<main>是HTML5的新添加,它包含网页或应用程序的主要内容。
有关main元素(以及其他元素)的更多信息,请访问www.quackit.com/html_5/tags/html_main_tag.cfm。
产品布局使用两列,以便将产品图像显示到产品信息的一侧(图2.13)。我们的样式表(第02章/资产/css/应用程序.css)已经定义了所有列样式,因此我们只需要在标记中包含适当的类名。
1使用v-bind指令将产品的图像路径绑定到img标签的src。
2其他产品属性使用v-text指令显示。
您马上就会注意到的一件事是在数据绑定中使用JavaScript点表示法。因为产品是一个对象,所以我们必须为每个绑定提供指向属性的整个路径。我们的产品数据title、description和price的大多数属性都是使用vtext指令绑定的,就像我们在标题中绑定sitename属性一样。
产品的图像路径引入了属性绑定。我们使用v-bind指令是因为不能使用简单的文本插值绑定元素属性。任何有效的元素属性都可以使用v-bind指令进行绑定,但需要注意的是,样式、类名和其他场景都有特殊情况,我们将在以后的章节中讨论。
您可以使用v-bind指令的缩写。您可以删除v-bind并键入:,而不是每次需要时都键入v-bind绑定:src=" ... ",您可以键入:src=“…”。
在绑定中使用表达式
我们不需要将数据绑定限制为数据的属性。Vue允许我们在任何绑定中使用任何有效的JavaScript表达式。使用清单2.5中的代码的几个示例可能是:
虽然以这种方式使用表达式很方便,但它将逻辑引入到视图中,而在负责视图数据的应用程序或组件的JavaScript代码中,这种逻辑通常更好。此外,像这样的表达式很难解释应用程序的数据在哪里被操纵,特别是当应用程序的复杂性增加时。
一般来说,使用内联表达式是在应用程序中形式化某个功能之前测试该功能的一种好方法。
下一节和接下来的章节将介绍操作、过滤和从现有值派生数据的最佳实践,而不会损害视图或应用程序数据的完整性。有关什么是表达式的详细信息,请访问https://vuejs.org/v2/guide/syntax.html#UsingJavaScriptExpressions。
让我们翻页到Chrome,重新加载页面,并确认产品信息显示为设计。
1过滤器选项包含输出过滤器。
2 formatPrice接受整数并格式化价格值。
3如果不能得到整数,请立即返回。
4种格式值1000美元及以上
5将值转换为十进制
6每三处加逗号
7返回格式化的值
8如果小于1000美元,则返回格式化的十进制值
formatPrice函数采用整数,并返回一个格式化为看起来像美元值的字符串。一般来说,它将返回类似于12345.67美元的价值。根据提供的整数的大小,函数分支如下:
1. 如果输入大于99999(相当于$999.99),则输出将需要在小数点左侧每隔三位使用逗号,因此我们需要相应地处理它。
2. 否则,可以使用.toFixed转换输入,并返回,因为不需要逗号。
2.4.2. 将过滤器添加到标记中并测试不同的值
要使用我们闪亮的新过滤器功能,我们需要将其添加到绑定中以获得产品的价格。我们还需要更新price绑定以使用Mustache样式绑定来应用过滤器,如下所示。筛选器不能与vtext绑定语法一起使用
记住,带过滤器的绑定具有一般形式{property | filter},因此我们相应地更新了价格绑定{产品价格|格式价格}。回到Chrome,刷新,瞧,我们得到了一个格式化的价格,如图2.15所示。
如果我们在控制台中修改数据,我们可以看到过滤器是如何实时应用于不同的产品价格值的。要尝试不同的值,请打开控制台并设置产品价格用这样的语句webstore.product.price = 150000000.
Figure 2.16 shows what will occur after the product price is updated. Be sure to try out small (< 100) and large (> 10000000) values to be sure each is formatted correctly.
摘要
Vue使您能够向应用程序添加交互性。
在任何时候,我们都可以连接到Vue生命周期,以帮助执行某些功能。
vue.js提供强大的过滤器,帮助以某种方式显示信息。
【第二部分:视图和视图模型】
这本书的重点在于视图和视图模型部分。这些章节将深入研究Vue以及构成Vue应用程序的所有元素和部分。我们将从简单开始,并为应用程序添加交互性。然后我们将讨论窗体和输入、条件和循环。
一些最重要的概念在第6章和第7章中,我们将深入研究组件。这些确实是我们应用程序的构建块。这是第一章,我们将在这里看到单文件组件—您的系统中的一个强大工具vue.js工具带。
最后两章将介绍转换、动画以及如何扩展Vue。这将使我们的应用程序更高效,看起来更漂亮。
第3章:添加交互性
本章涵盖:
- 从具有计算属性的数据导出新输出
- 向DOM添加事件绑定
- 在Vue生命周期的更新部分观察数据
- 响应用户交互
- 有条件呈现标记
信不信由你,现在我们已经把第一个产品都连接好了,我们已经准备好为我们的网站商店添加交互了。
向应用程序添加交互性意味着绑定到DOM事件,在应用程序代码中响应它们,并向用户提供关于由于其操作而发生的事情的反馈。Vue为我们创建和管理所有事件和数据绑定,但是我们需要做出一些决定,即如何在应用程序中操作数据,以及如何在界面中满足用户期望。
我们将开始探索用户交互,让客户将我们的单个产品添加到购物车中,但在此过程中,我们还将研究如何将我们的工作融入Vue应用程序的整体图景。
为了了解我们在本章中的发展方向,图3.1显示了在完成所有工作后应用程序的外观。
3.1. 购物车数据从添加数组开始
在构建任何超级酷购物车功能之前,我们需要一个容器来存放应用程序实例中的所有项目。幸运的是,在这个阶段我们只需要一个简单的数组,我们将把产品推到这个数组上。
我把代码分解成小片段,类似于我们在上一章中所做的那样。你需要把这些添加到你的index.html您创建上一章以继续应用程序的文件。如果需要,您可以始终下载本章的代码。
1显示我们现有的产品数据,供参考
2显示了一个用于存放购物车项目的数组
我们的购物车。完成。不过,认真地说,我们将从这个简单的数组中获得很好的效果,但最终我们将创建一个cart组件,该组件将在内部管理其内容。
3.2. 绑定到DOM事件
为了向应用程序添加交互,我们需要将DOM元素绑定到在Vue实例中定义的函数。我们可以使用事件绑定将元素绑定到任何标准的DOM事件click、mouseup、keyup等。Vue负责引擎盖下的所有布线,因此我们可以关注应用程序在事件发生时如何响应。
以下是事件绑定的JavaScript的两种常见模式:
1. 使用函数名,我们可以将事件绑定到实例中定义的函数。如果我们有一个绑定,比如von:click=“clickHappened”,那么单击元素就会调用函数clickHappend。
2. 我们可以编写作用于公开属性的内联JavaScript。在本例中,绑定可能看起来像v-on:keyup=“charactersRemaining-=1”,这会将charactersRemaining属性减少1。
每个策略在应用程序中都有自己的位置,但首先我们要看看如何使用函数来处理事件。
请注意,有一种更简单的简写方法来编写v-on指令。你可以用@符号代替v-on。例如,如果你想使用v-on:click=“…”你可以用@click=“…”代替它。我们稍后会在书中用这个速记法。
1 该methods对象包含我们的新函数。
2 定义addToCart函数
目前,将产品添加到cart意味着将产品的id属性从产品数据推送到cart数组中。请记住,您需要添加this关键字才能访问所有数据属性。
看起来似乎将整个产品对象添加到我们的购物车数组更简单:this.cart.push(this.product);---但是如果我们这么做,事情将会变得有点尴尬。JavaScript既不是一个纯粹的pass-by-reference引用语言,也不是一个纯粹的pass-by-copy复制语言,所以可能需要一点练习才能知道是否会发生。
将产品推送到cart数组将推送到数据中定义的产品对象的引用,而不是副本。如果数据中的产品定义发生了变化,那么当我们从服务器检索新的产品数据时,它可能会在购物车中被替换,或者引用可能会变得未定义。
相反,通过将产品id推送到cart数组中,我们推送的是产品id值的副本,而不是引用。如果产品定义更改,则cart数组中的值保持不变。
从技术上讲,JavaScript是一种call-by-sharing呼叫共享语言。你可以在维基百科上找到一个关于呼叫共享的简要解释,以及它与其他策略的比较https://en.wikipedia.org/wiki/Evaluation#strategy#Call#by#u sharing。
现在我们有了一个函数,可以将产品添加到购物车中,这样我们就可以继续添加按钮标记了。在我们的product div中的价格加价之后,添加这个列表中的按钮。
现在,单击addtocart按钮几次。打开vue-devtools窗格并单击<Root>。您应该看到每次单击都会将产品的id推送到阵列上,如图3.4所示。
使用vue-devtools或控制台查看购物车中有多少项目对开发人员来说可能没问题,但是客户需要视图本身的反馈。是时候添加项目计数器了。
1 fullName返回用户的名字和姓氏的值,由单个空格连接。
fullName函数返回的结果在概念上等同于在数据对象中具有fullName属性,这意味着我们可以轻松地绑定到标记中(见图3.5)。
使用计算属性的另一个好处是,我们可以更改函数的内部结构,以使用来自应用程序的不同或附加数据。例如,在图3.5中,我们可以使用prefix属性为用户的全名添加更多的形式。
以这种方式使用计算属性,我们可以组合或以其他方式操纵任何实例数据,而无需更改后端或数据库。
3.3.2. 检查具有计算属性的更新事件
因为计算属性通常是使用实例数据计算的,所以当基础数据更改时,它们的返回值会自动更新。因此,绑定到computed属性的任何视图标记都将更新以反映新值。
在更大的Vue实例生命周期中,此行为是更新周期的核心。为了了解更新周期的行为,让我们通过另一个示例来了解计算属性何时最适合该作业。考虑根据矩形的长度和宽度计算矩形面积的任务。
1显示包含长度和宽度属性的数据对象
2显示一个计算属性,该属性公开的区域与数据属性相同
计算的物业面积的初始值为15。对长度或宽度的任何后续更改都会触发对应用程序的一系列更新:
1. 当长度或宽度的值改变时。
2. . . . 重新计算计算的属性区域。
3. . . . 然后将更新绑定到这些属性的任何标记。
图3.6显示了应用程序的更新周期。
通过使用watch函数观察实例中的数据何时发生更改,以及beforeUpdate lifecycle钩子(应该只在数据发生更改后执行),我们可以看到生命周期的运行情况。
watch函数的工作方式与lifecycle钩子相同,但当它“监视”的数据更新时会触发。我们甚至可以创建一个watch函数来观察计算的属性。
清单3.6将面积计算放在一个完整应用程序的上下文中。该应用程序还包含三个监视函数,在长度、宽度或区域发生变化时将消息记录到控制台,以及一个在更新周期开始时记录消息的函数。必须在Vue实例的watch选项中指定这些函数才能工作。
1列出显示区域值的数据绑定
2显示分别将“长度”或“宽度”值增加1的按钮
3显示长度和宽度的原始值
4给出了面积计算属性
5显示在长度更改时记录的函数
6显示宽度变化时记录的函数
7显示区域更改时记录的函数
8列出了beforeUpdate lifecycle钩子函数
当您在Chrome中加载这个文件时,您将看到area的初始值是15,如图3.7所示。确保JavaScript控制台已打开,然后尝试单击按钮触发更新周期。单击addlength按钮和addwidth按钮时,控制台应该记录有关应用程序数据的消息(参见图3.8)。
现在我们已经看到了应用程序的行为,我们可以将清单3.6中的数据和函数映射到图3.9中的更新周期图上。
Figure 3.9. Changes in an instance’s data trigger a cascade of activity within the update cycle of an application.
最后要注意的一点是,如果从示例代码中删除{area}绑定,并在浏览器中重新加载页面,那么当您单击任一按钮时,您将看到控制台输出中的差异(参见图3.10)。
3.3.3. 显示购物车项目计数和测试
现在我们已经对计算属性有了很好的理解,让我们再次看看购物车示例。让我们向Vue实例添加一个computed属性,该属性将显示购物车中的项目数,如下面的清单所示。别忘了在options对象中添加一个computed对象,这样我们的函数就有了生存的空间。
1添加计算对象
2返回购物车数组中的项目计数
这是计算属性的简单用法。我们使用数组的现有JavaScript属性长度来检索计数,因为实际上不需要为购物车添加我们自己的计数机制。
这也是一个很好的例子,说明为什么不适合将此类数据存储为数据对象的属性。因为cartItemCount的值是用户交互的结果,而不是来自数据库的结果,所以我们不希望在数据对象中看到它。
值得注意的是,有时这样的项计数可能在数据对象中。例如,如果用户正在查看“以前的订单”页面,则可能存在与每个订单相关联的项目计数。这与我们到目前为止的想法是一致的,因为在处理和持久化订单之后,数据将来自数据库。
功能到位,我们准备在应用程序的头上添加一点HTML,这样我们就可以有购物车和一个显示项目计数的地方。更新标题中的标记,如此处所示。
1将我们的购物车向右对齐
2显示计算属性的数据绑定
我们向头添加了一个新的div元素,这样我们就有了一个放置cart的位置,并且我们使用cartItemCount绑定来显示computed属性的值。绑定被一个span元素包围,这个元素用作样式挂钩,在我们的计数器旁边添加一个cart图标。是时候测试一下了。
在Chrome中重新加载webstore应用程序后,单击addtocart应该会导致指示器随着每次单击而增加。您可以通过再次检查控制台中的cart数组来再次检查计数是否正确(参见图3.11)。
3.4. 为我们的按钮添加用户可承受性
当人们到达一个网站或使用一个web应用程序时,他们带来了各种各样的体验和期望。其中一个最基本的、根深蒂固的问题是,当交互元素的行为与预期不同时,产品可能会感到支离破碎或迷失方向。用户可承受性背后的思想是向用户提供视觉(或其他)提示和反馈,以使我们的应用程序与他们的期望保持一致。
我们现在有一个按钮,让客户无休止地添加一个产品到他们的购物车。限制顾客可以购买的商品数量可能有很多原因:有限的可用产品、对每位顾客购买的限制、数量折扣等等。如果数量有限,则“添加到购物车”按钮应在某个点不可用,或者以其他方式指示该操作不再可能。
为了完成这项任务,我们需要跟踪可用的库存,将其与购物车中的产品实例数量进行比较,并采取措施防止客户添加的产品数量超过可用的数量。让我们从跟踪库存开始。
3.4.1. 关注库存
为了防止客户购买过多的给定产品,我们需要向product对象添加一个新属性,如下面的清单所示。availableInventory属性将表示我们商店有多少个单独的产品单位可用。
如果另一个客户在交易过程中购买了一个或多个相同的产品,那么在完成购买时仍有必要再次检查产品的可用性,但我们可以在应用程序中实现一个简单的解决方案,以大大减少用户稍后因隐藏或禁用而失望的机会,添加到购物车按钮。
3.4.2. 使用计算属性和库存
我们不想改变availableInventory值,因为它表示一个固定值,该值只能由一个管理实际库存的过程来更新(这一点我们将在本书的稍后部分进行讨论)。但我们确实希望根据可用投资的价值来限制客户可以添加到购物车中的产品数量。
要做到这一点,我们需要一种方法来跟踪客户购物车中相对于固定数量的可用产品的商品数量。我们将使用computed属性实时执行此计算,因为客户将商品添加到他们的购物车中。
1使用canAddToCart计算属性
2将可用库存与购物车中已有的物品数量进行比较
因为我们的代码可以以与实例数据属性相同的方式使用计算属性,所以我们有机会在另一个计算属性中利用一个计算属性cartItemCount。我们的新计算属性检查可用库存是否大于购物车中已有的商品数量。如果没有,这意味着客户已经将最多数量的产品添加到他们的购物车中,我们将不得不采取行动阻止他们添加更多的产品。
JavaScript中的“真实性”
您可能已经意识到,在JavaScript中计算表达式的真值可能有点棘手。下面是一个简单的例子,你可以自己在控制台中尝试。
当使用非严格相等运算符==时,与字符串值“1”相比的整数值1的计算结果为true。之所以会出现这种情况,是因为JavaScript试图“提供帮助”,在计算比较之前进行类型转换。使用严格相等运算符===会产生预期的错误结果。
在canAddToCart函数中,我们使用大于运算符>来比较两个整数值。如果我们对这些值的来源有任何疑问,或者它们实际上是整数,我们可以使用parseInt方法强制转换,或者确保这些值是整数。
1 v-show指令绑定到我们的canAddToCart计算属性。
如果您在Chrome中重新加载应用程序并尝试向您的购物车中添加六种产品,则在第五次单击时按钮应该消失,因为这是availableInventory的值,如图3.12所示。
1 避免在相邻元素上使用v-show指令。
2 取而代之的是,包装相邻的元素,并使用单个v-show指令。
要清楚的是,在应用程序中使用vshow是可以的。只要有可能,最好将对数据作出反应的多个元素聚合在一起,这样既可以获得更好的性能,又可以减少在进行更改时忘记更新所有元素的机会。当库存耗尽时删除addtocart按钮当然可以,但这有点过分。我们换个方法试试。
3.4.4. 使用v-if和v-else显示禁用的按钮
删除addtocart按钮当然可以防止客户向cart添加太多的产品实例,但这有点太过繁重了。对用户来说,禁用按钮可能更有用,因为这样不会破坏界面的连续性,并且可以保留布局流。
v-if和v-else指令用于根据所提供表达式的真值显示两个选项之一。我们将使用canAddToCart作为评估的条件,就像我们在前面的示例中所做的那样。
在图3.13中,您可以看到v-if指令是如何工作的。如果canAddToCart为true,则会显示按钮,否则不会显示按钮。
在这个清单中,我们可以看到这是如何处理我们的v-if和v-else指令的。
Listing 3.13. Buttons with v-if and v-else directives: chapter-03/v-if-and-v- else.html
1当canAddToCart返回true时,将显示该按钮。
2 canAddToCart为false时显示的按钮。
当同时使用v-if和v-else时,我们的标记中需要两个元素,一个用于条件为真时,另一个用于条件为假时。此外,这两个元素需要在标记中一个接一个地列出,以便Vue正确地绑定到它们。
在清单3.13中,我们使用两个不同的按钮元素:
- 如果canAddToCart返回true,我们将使用addToCart事件绑定和默认CSS类呈现我们熟悉的按钮。
- 如果canAddToCart返回false,我们将呈现一个没有事件绑定的按钮,这样它就变得不可访问,并且带有一个禁用的CSS类,这样它的外观就会相应地改变。
这一次,当你在Chrome中试用这个应用程序时,一旦你在购物车中添加了五种产品,这个按钮就会将活动按钮(图3.14)切换到禁用按钮。
Figure 3.14. Using v-if and v-else means we can render a disabled button, rather than making it disappear entirely when the inventory is exhausted.
使用v-if和v-else指令,vue.js从DOM中删除元素(假条件)并从另一个DOM中删除它(真条件)。所有这些都是作为对DOM的一次同步更新的一部分来完成的。通过在控制台中摆弄availableInventory的值并关注这些元素的display属性来尝试一下。
与v-show指令一样,必须有一个包含元素将v-if和v-else元素附加到,特别是在附加的标准下,v-else标记必须保持与v-if标记相邻,如图所示。
1 如果vif和velse被第二段元素分解,这就行不通了。
2 如果vif和velse在标记中不相邻,则这将不起作用。
3 这将工作;在元素中包装相关内容,然后将vif和velse绑定到该元素。
这里的目标是将给定条件的所有DOM元素保留在用作分组容器的外部元素中。稍后,我们将探讨使用模板或组件隔离条件标记的不同策略,从而大大简化主应用程序本身所需的标记量。
3.4.5. 将购物车项目按钮添加为切换
让我们为结帐页面添加一个按钮。我们将首先向应用程序添加一个新方法和属性。
1此属性跟踪是否显示产品页。
2单击购物车按钮后会触发showCheckout方法。
3显示在真与假之间切换的三元运算
新的showProduct属性将切换签出页的显示。让我们更详细地看一下。showCheckout方法通过在JavaScript中使用称为三元操作的操作来切换showProduct属性。三元运算符是if语句的快捷方式,它有三个参数。第一个参数是条件,在这种情况下,此.showProduct. 如果解析为true,则返回第一个表达式false。否则返回最后一个表达式true。当您需要创建一个快速的条件语句时,三元条件运算符是一个非常有用的工具。
您可能已经注意到方法定义在showCheckout()之后缺少function()声明。ES6(也称为ES2015)允许使用较短的方法定义语法。在本书的其余部分中,我们将在方法定义中使用这种语法。
我们现在需要将按钮添加到视图中,并将其绑定到click事件:
1 vif指令,如果showProduct为true,则显示该指令。
2显示视图的产品列表,包括产品的图片和说明
3这是结帐页面的位置。
在本章前面,我们创建了一个checkout按钮。按下此按钮时,showProduct属性将从true切换到false,或从false切换到true。这将触发清单3.17中的v-if指令。我们在本章中创建的产品信息将显示出来,或者只显示顶部导航的空白屏幕(图3.15)。
现在,不要担心我们在图3.15中看到的空白页面。在下一章中,当我们研究不同类型的输入绑定时,这一点将得到关注。
3.4.7. v-show与v-if/v-else的比较
这两种技术——v-show和v-if/v-else——对用户和我们作为开发人员都有优点和缺点。如我们所知,v-show指令使用CSS隐藏或显示元素,而v-if/v-else指令从DOM中删除内容。也就是说,理解什么时候使用一个或另一个主要取决于我们试图实现什么,所以比较它们的最佳方法可能是为每个用例考虑几个用例。
v-show指令最适合于没有“else”情况的场景。也就是说,当您有标记来显示条件是否为真,而没有其他内容来显示条件是否为假时。以下是几个可能的用例,其中v-show是正确的选择:
- 一个信息横幅的东西是暂时的,如一个销售公告或条款和条件的变化。
- 一个注册广告,或其他诱因,当一个访问者没有登录。
- 跨多个页面运行的列表的分页元素,如果只有一个页面,这将是多余的。
当呈现两个标记块中的一个时,vif和velse指令是正确的选择,但至少应该始终显示其中一个。如果没有回退(else)情况,那么vshow更合适。这里有几个应该使用vif和velse的场景:
- 显示已注销用户的登录链接,而显示已登录用户的注销链接。
- 根据用户所做的选择呈现表单的条件部分,例如特定于国家的地址字段。例如,美国地址表显示“州”字段,加拿大地址表将其显示为“省”
- 未进行搜索时,搜索结果列表与占位符内容。(在后面的一章中,我们将探讨使用velseif添加第三状态的示例。)
无休止的场景存在,你需要使用一个或另一个条件。考虑哪一个适合您的需要的最佳方法可能是考虑是否有要显示的内容块的回退或默认值。接下来,我们将通过提供不止一袋猫粮,让我们的网络商店对潜在客户更加有用。
- 将值绑定到DOM
- 使用文本绑定
- 修饰语
我们的应用程序从第一章开始有了实质性的发展。我们已经创建了项目,并允许用户将项目添加到购物车。我们现在需要一种方式让我们的客户签出并输入他们的信息。让我们将输入表单添加到我们的应用程序中,以便客户可以在应用程序中输入他们的地址和帐单信息。然后我们需要将这些信息保存在我们的应用程序中以供以后使用。
为了实现我们的目标,我们必须在应用程序中将表单数据绑定到我们的模型。v-model指令就是为这个用例设计的。
定义:v-model指令在表单或文本区域输入和模板之间创建双向数据绑定。这确保了我们的应用程序模型中的数据始终与我们的UI保持同步。
双向数据绑定与单向数据绑定
在实践中,双向数据绑定(图4.1)可能是最好的解决方案,也可能不是。在某些情况下,从用户输入捕获数据后,数据将不需要更改。其他框架和库,如React和Angle2默认情况下选择了单向数据绑定。Angle1从双向绑定开始,在构建Angle2时出于性能管理原因放弃了它。单向数据绑定y历史主题学习路径提供&交易突出显示当输入更改时捕获的数据未从模型同步到视图时支持签出的设置。需要添加额外的逻辑,以便在模型或视图中更改值。余烬.js默认情况下,决定坚持双向数据绑定。使用v模型指令,数据绑定有两种方式。不管怎样,我们都可以使用vonce指令将属性指定为Vue中的单向绑定。
Figure 4.1. The model updates the view while the view updates the model.
v-once指令只呈现元素或组件一次。在任何其他重新呈现时,元素或组件将被视为静态内容并被跳过。要了解有关v-once指令的更多信息,请查看官方API文档https://vuejs.org/v2/api/#vonce。
在本书的后面,我们将讨论组件属性以及如何将它们传递给其他组件。这些属性在父属性和子属性之间形成单向绑定。这将在将来变得有用。
v-model指令用于各种表单输入,包括文本框、文本区域、复选框、单选按钮和选择下拉控件。我们需要所有这些元素来构建新的签出checkout表单。让我们看看如何使用v-model指令,以及它如何处理绑定输入。
首先,我们需要在应用程序中添加新的HTML。打开index.html您在上两章中创建的页面,并查找velse指令(或者您可以下载提供的index.html第3章的文件)。在这个<div>标记中,我们将在本章中添加HTML代码。在第7章中,我们将讨论将应用程序分解为组件的更好方法。现在,我们将使用简单的vif指令作为切换来显示签出页面。
与前几章一样,每个代码段都被拆分为自己的文件。请把这个和这个结合起来index.html创建已完成的应用程序。
Listing 4.1. A vmodel directive with first and last name inputs: chapter-04/first- last.html
1.firstName和lastName使用vmodel绑定。
2.随着输入值的变化,firstName和lastName属性将实时显示。
代码为名字和姓氏创建两个文本框,每个文本框绑定到实时同步的属性。这些属性是在数据对象中创建的。为了简化这个过程,我们将使用order属性将这些值保存在Vue实例数据对象中。这将添加到index.html文件。
在数据对象中,我们需要添加新的order属性。我们需要这个order属性,这样就可以跟踪名字和姓氏。将以下代码添加到现有的索引.html我们在上一章中使用的数据对象。
此列表中的order对象位于Vue构造函数内的数据对象中。我们可以使用第2章中学习的双花括号Mustache语法{{}}在整个代码中引用这个对象。例如{{订单名}}将替换为order对象中的名字。将我们的订单信息保存在一个对象中可以更容易地理解数据在将来的位置。
值得一提的是,我们可以在这里使用空的order对象,而不是在其中显式定义firstName和lastName属性。vue.js可以隐式地将属性添加到对象。为了简单起见,为了让代码库更干净一点,我们将添加属性,这样我们就可以看到一切是如何工作的。
在我们的checkout表单中输入数据之后,注意值实时出现在框中(图4.3)。这就是双向数据绑定的美妙之处。值之间自动同步,无需任何其他逻辑。
我们现在有了结帐页面的开始。让我们将更多表单输入添加到index.html文件,以便我们的客户可以添加他们的地址信息,如下所示。我们可以在清单4.1中添加的HTML代码之后添加这个HTML。
您可能想知道,我们如何轻松地将更多状态添加到select下拉控件中。对于这个简单的例子,硬编码所有四个状态是好的。但是,如果我们要添加所有50个状态,我们可能需要动态生成选择框。在下一节中,我们将研究如何使用值绑定来帮助生成动态选项。
在继续之前,不要忘记将新属性添加到Vue实例中的数据对象。
如图4.3所示,如果这些属性中的任何一个在表单元素中发生了更改,那么这些值将在底部的<pre>标记中更新。重新加载浏览器,新表单应该如图4.4所示。
1. Checkbox
2. radio
3. pre
让我们通过添加以下代码将属性添加到数据对象。
您可能注意到我们为方法和礼物添加了默认值。这背后的原因很简单。默认情况下,选择“方法”单选按钮,并且未选中复选框。因此,我们现在在这个代码中设置默认值是明智的。
最后一件事,我们需要做的是添加一个Place Order(提交)按钮。现在,我们将模拟按钮,以便将来使用它。有几种方法可以创建placeorder按钮。您可以将动作附加到包含所有输入的表单元素。(我们将在关于事件的第6章中进一步了解这一点。)相反,让我们使用我们在第3章中首先了解的von指令。von指令可以将函数绑定到应用程序中的DOM元素。将其添加到PlaceOrder按钮上的click事件。这个HTML代码可以在清单4.5之后添加。
在以后的章节中,我们将为placeorder按钮添加功能。出于我们现在的目的,让我们创建一个简单的函数,并通过添加一个警报弹出窗口来验证按钮是否有效。将submitForm函数添加到index.html文件,如清单所示。
在Vue构造函数中是methods对象,它保存了可以在应用程序中触发的所有函数。submitForm函数在触发时将显示一个警报弹出窗口。在浏览器中,单击PlaceOrder按钮,您将看到submitForm函数触发的弹出窗口(图4.5)。
现在我们已经有了一个placeorder按钮的表单,当它全部放在一起时,它应该像图4.6所示。
1.设置oder.sendGift属性
2.设置order.dontSendGift属性
3.绑定order.gift到输入input
为了使这个绑定如我们所期望的那样工作,我们需要将这些新属性添加到order对象中,如下一个清单所示。更新中的order对象索引.htmlsendGift和dontSendGift属性的值。
1.复选框的默认值默认为“ Send As A Gift”复选框。
2.order.sendGift属性是选中复选框时显示的文本消息。
3.order.dontSendGift属性是未选中复选框时显示的文本消息。
我们的数据对象越来越大了!如果选中或不选中复选框,我们现在可以指定文本值。刷新页面并取消选中“作为礼品发货”复选框。查看底部的框(图4.7);我们将看到{{订单.礼品}}属性。
4.2.2 使用值绑定和单选按钮
像复选框一样,我们可以给单选按钮赋值。我们可以通过直接绑定值来实现这一点。这对于我们的应用程序来说可能是一个有用的特性。如果用户选择了home单选按钮,我们将向用户显示home address;如果用户选择business单选按钮,我们将向用户显示business address。将此HTML添加到索引.html在上一个复选框代码之后。
1. 将vbind指令设置为第一个单选按钮的输入元素的value属性
2. 将vbind指令设置为第二个单选按钮的输入元素的value属性
v-bind指令绑定order.home到第一个单选按钮,order.business到第二个单选按钮。这可能很强大,因为我们可以随时动态更改这些值。
为了完成这个示例,让我们将这些新属性添加到index.html,如下表所示。
1. 默认值为Home Address
2. 第一个单选按钮选中时显示order.business属性。
3. 第二个单选按钮选中时显示order.home属性。
这个新的order对象现在有几个新的属性home和业务,它们绑定到单选按钮。如果选择其中一个,底部的值将在主地址和业务地址之间切换(图4.8)。
我们的客户可以看到,他们有一个包裹被送到一个营业地址(埃里克汉切特在123街Ln,雷诺,内华达州),它不会作为礼物运送!将属性绑定到表单中的任何属性值都可以使事情变得更清晰和简单。我们现在需要在下一节中查看美国各州的选择框控件。
1 将vbind指令值属性赋给states.AL属性
2 将vbind指令值属性分配给states.AR属性。
3 将vbind指令值属性指定给states.CA属性。
4 将vbind指令值属性分配给states.NV属性。
正如我们之前看到的,vbind指令正在分配value属性。这次我们创建了一个名为states的新数据属性。在这个州的财产里,我列出了美国的州。states对象包含四个值。我们可以使用vbind指令在选择框中访问它们。更新索引.html文件并将states对象添加到data对象。
更新完所有内容后,我们应该在页面底部模板的文本框中看到这些值(图4.9)。正如你所看到的,国家是明确的,清楚地表明发生了什么。
在本章的前面,我提到了下拉列表中的一个关键问题。在本例中,只列出了四个状态。随着状态列表的增长,我们需要为每个状态创建一个option>标记。这可能是乏味和重复的。幸运的是,Vue有一些东西可以帮助我们解决这个问题。它被称为v-for指令。
v-for指令使得在列表或对象中循环值变得很容易,这非常适合我们的情况。为了实现这一点,我们将在state对象中定义所有状态。然后,我们将在使用vbind指令时迭代每个状态,以便所有内容都匹配。我们来试试吧!
这里发生了很多事情,所以我来细说一下。v-for指令要求以state in states的形式使用特殊语法。states是源数据数组,而state是正在迭代的数组元素的别名。在这种情况下,州是阿拉巴马州,亚利桑那州,加利福尼亚州,等等。替换index.html在城市输入之后,使用如下所示的HTML。
1 v-for指令循环遍历states获取到每个key和value
2 v-bind指令的value属性赋值给state属性.
3 key属性显示。
键值是一个可选参数,用于指定当前项的索引。这在select下拉控件中很重要,因为键值可以用作缩写状态,而实际值是完整的状态名。
v-bind指令将state的值绑定到<option>标记上的值,如清单4.16所示。在应用程序中替换此代码后,请查看通过打开web浏览器并查看源代码生成的HTML索引.html. <option>标记将显示states属性中的每个状态。
这对我们的应用来说是个好消息。因为我们现在可以绑定这些值并用v-for对它们进行迭代,所以我们不再需要硬编码每个美国州。我们的选择框可以根据创建states对象的方式动态增长。
1. 使用state in states语法的v-for指令。
states数组有五个值。让我们创建一个有序列表来显示每个项目。我们没有钥匙,所以不用担心。要创建列表,我们将使用<ol>和<li>标记。将这些标签添加到新标签的顶部detour.html文件。
v-for指令遍历states数组并显示列表中的每个状态。请记住,state是要迭代的数组元素的别名,而states是数组项。很容易弄糊涂,记住别名总是先出现,然后是可选键,然后是迭代的数组或对象。
呈现时,我们将看到一个有序编号列表中的州列表,如下所示:
我们现在可以通过向states对象添加值来扩展列表,而无需更改模板。
您可能会遇到需要直接操作DOM的情况,并且可能不想使用v-model指令。在这种情况下vue.js给我们提供了$el。您可以在Vue实例中使用$el。这将是Vue实例正在管理的根DOM元素。在那里,您可以运行任何类型的文档方法,比如querySelector(),来检索您想要的任何元素。记住,如果可以的话,试着使用内置的vue.js使用DOM时的指令。他们在那里让你的工作更轻松!有关$el和其他API的更多信息,请访问官方API文档https://vuejs.org/v2/api/。
4.3. 学习使用应用程序修饰符
正如本章前面提到的,v-model指令可以绑定到我们的输入值。这些值随每个输入事件而更新。我们可以在v-model指令中使用修饰符来改变这种行为。例如,我们可以使用.number和使用trim将值类型转换为数字(有关修饰符的更多信息,请转到https://vuejs.org/v2/guide/forms.html#Modifiers). 我们也可以通过一个接一个地添加链式修饰语(例如,vmodel.trim.number). 让我们在应用程序的checkout页面中添加几个这样的修饰符。
4.3.1. 使用.number修饰符
.number修饰符用于自动将vmodel指令中的值类型转换为数字。这在我们的ZIP输入框中很有用(我们假设应用程序中的邮政编码不是以零开头的,否则.number修饰符会删除前导的零)。让我们更新邮箱里的邮政编码索引.html文件来使用.number修饰符,并在下面的列表中查看它的效果。
Listing 4.18. The .number modifier on the ZIP form element: chapter-04/number-mod.html
1. 显示带有.number修饰符的v-model指令
HTML输入总是以字符串的形式返回,即使您添加type=“number”。添加.number修饰符可防止此行为,而是以数字形式返回。为了验证这一点,让我们更新索引.html在显示订单.zip属性。
1 JavaScript typeof运算符返回未赋值操作数的类型。
在我们添加.number修饰符之前,它会显示为一个字符串。现在它以数字的形式返回。在ZIP输入框中输入一个数字,然后重新呈现页面以查看新的输出,如图4.10所示。
您可以在图4.10中看到ZIP列显示的数字。因为我们将邮政编码包装在typeof操作数中,所以它向我们显示了该属性的类型。稍后我们将使用此功能;现在我们将删除typeof操作数,以便它返回邮政编码。从中删除操作数的类型订单.zip所以剩下的就是财产{{订单.zip}}.
4.3.2. 修剪输入值
在提取表单信息时,我们通常不使用前面的空格或输入文本后的空格。如果一个用户在输入他们的名字之前不小心输入了几个空格,我们需要删除它们。vue.js提供了一个很好的修改器,可以自动从输入中修剪空间。
在我们的应用程序中,我们使用输入字符串文本框来表示名字、姓氏、地址和城市。在下面的清单中,让我们更新index.html中的姓名,查看.trim修饰符的工作方式。
Listing 4.20. The .trim modifier on first and last name: chapter-04/trim-mod.html
1 vmodel指令将.trim修饰符用于订单名财产。
2 vmodel指令将.trim修饰符用于订单.姓氏指令。
要添加.trim修饰符,我们只需要在v-model指令的末尾添加.trim。这将自动为我们修剪空白!现在我们可以将它添加到index.html.
1 vmodel指令将.trim修饰符用于order.address属性。
2 vmodel指令将.trim修饰符用于order.city指令。
如果我们在浏览器刷新后查看页面底部的输出,我们会注意到空白被删除(图4.11)。
练习
使用本章学的知识回答以下问题:
双向数据绑定怎么工作的?为什么你应该在你的vue.js应用中使用它?
第五章:条件、循环和列表
- 使用条件句v-if和v-if-else
- 使用v-for循环
- 查看Array更改
在上一章中,我们看到了v-model指令的强大功能,以及如何使用它将输入绑定到应用程序。我们构建了一个签出页面,其中显示了我们需要从用户那里收集的所有输入表单。为了显示这个页面,我们使用了一个条件语句。
在第3章中,我们创建了一个绑定到click事件方法的checkout按钮。此方法使用名为showProduct的属性进行切换。在我们的模板中,我们使用了v-if指令和v-else指令。如果showProduct为true,则显示“product”页面(如果showProduct为false),则显示checkout页面。通过单击checkout按钮,用户可以轻松地在这些页面之间切换。在后面的章节中,我们将研究重构此代码以使用组件和路由,但目前这将起作用。
为了扩展我们的应用程序,我们将研究其他类型的条件句。例如,我们需要添加一个新功能,根据可用的库存级别向用户显示消息。此外,我们需要添加更多的产品到我们的产品页面。我们将在第5.2节中更详细地了解这一点。