zoukankan      html  css  js  c++  java
  • Vue实战

    前言

    在你学习如何制作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/vue­js­in­action)和我的个人GitHub存储库(https://github.com/ErikCH/VuejsInActionCode). 您还可以在附录A中找到有关下载代码和设置编程环境的更多说明。

    在线资源

    正如我前面提到的,在线资源vue.js官方指南是很好的使用作为参考,而你在工作的例子在书中。你可以在https://vuejs.org/v2/guide/。它们不断更新。

    https://github.com/vuejs/awesome­vue有一个列表与Vue.js相关的好东西. 在这儿, 你可以发现Vue.js 广播, 额外的Vue.js资源, 第三方的类库, 甚至是使用Vue.js的公司. 我强烈建议你看一下。

    Vue.js的社区很大,而且持续增长。最好的一个社区是官方的vue.js论坛:https://forum.vuejs.org/
     
    如果你寻找更多视频教程,我的频道,http://erik.video在YouTube,覆盖了关于Vue.js和JavaScript。来看一下吧!
     
    【第一部分:了解vue.js】
     
    在我们学习Vue提供的所有酷的东西之前,我们需要先了解它。
    在前两章中,我们将了解其vue.js背后的哲学,MVVM模式,以及它与其他框架的关系。
    一旦我们了解了Vue的来源,我们将更深入地研究Vue实例。根Vue实例是应用程序的核心,我们将探讨它的结构。稍后,我们将研究如何将应用程序中的数据绑定到Vue。
    这些章节将给你一个很好的开始vue.js. 您将学习如何创建一个简单的应用程序以及Vue的工作原理。
     
    第1章: 介绍Vue.js
     
    本章将探讨:
    • MVC和MVVM设计模式
    • 这些模式定义一个反应式应用程序
    • 描述Vue生命周期
    • 评估vue.js
    交互式网站已经存在很长时间了。在2000年代中期web2.0的初期,人们更关注的是交互性和吸引用户。Twitter、Facebook和YouTube等公司都是在这段时间创建的。社交媒体和用户生成内容的兴起正在使网络变得更好。
     
    开发人员必须跟上这些变化,为最终用户提供更多的交互性,早期,库和框架开始使交互式网站更容易构建。2006年,johnresig发布了jQuery,大大简化了HTML的客户端脚本。随着时间的推移,越来越多的客户端框架和库被创建。
     
    起初,这些框架和库是庞大的、单一的、固执己见的。现在,我们已经看到了向更小、更轻的库的转变,这些库可以很容易地添加到任何项目中。这就是vue.js进来了。
     
    vue.js是一个库,它使我们能够将交互行为和功能添加到JavaScript可以运行的任何上下文中。VUE可以在单个网页上用于简单的任务,也可以为整个企业应用提供基础。
     
    从访问者与之交互的界面到为我们的应用程序提供数据的数据库,我们将探讨Vue及其支持库如何使我们能够构建完整、复杂的web应用程序。
     
    在此过程中,我们将每一章的代码如何适应整个大项目,哪些是行业的最佳实践,以及您如何将我们正在进行的工作合并到您自己的现有和新项目中。
     
    这本书主要是为那些对JavaScript有一定程度的熟悉并对HTML和CSS有良好理解的web开发人员编写的。也就是说,由于其应用程序编程接口(API)的多功能性,Vue是一个随着项目的发展而发展的库。任何人谁想要建立一个原型或个人侧项目的应用程序应该找到这本书的旅程可靠的指南。
     
    1.1. 在巨人的肩膀上
     
    在为我们的第一个应用程序编写任何代码之前,甚至在更高层次上深入研究Vue之前,了解一点软件历史是很重要的。如果不了解web应用程序在过去所面临的问题和挑战以及Vue带来的优势,就很难真正理解Vue为我们做了什么。
     
    1.1.1. 模型-视图-控制器模式(MVC)
     
    客户端模型-视图-控制器(MVC)模式是对其实用性的证明,它提供了许多现代web应用程序开发框架所使用的体系结构蓝图。(如果您熟悉MVC,可以跳过。)
    值得一提的是,在我们继续之前,最初的MVC设计模式已经改变了很多年。有时被称为经典MVC,它涉及一组关于视图、控制器和模型如何交互的独立规则。为了简单起见,我们将讨论客户端MVC模式的简化版本。这种模式是对网络的一种更现代的解释。
    如图1.1所示,该模式用于分离应用程序的关注点。视图负责向用户显示信息。这表示图形用户界面(GUI)。控制器在中间。它有助于将事件从视图转换到模型,并将数据从模型转换到视图。最后是模型包含业务逻辑,也可以包含一种数据存储。
    在现代软件开发中,MVC模式经常被用作单个应用程序的一部分,并为分离应用程序代码的角色提供了一种很好的机制。对于使用MVC模式的网站,每个请求都会启动一个信息流,从客户机到服务器,再到数据库,然后一路返回。这一过程耗时、资源密集,而且无法提供快速响应的用户体验。
    多年来,开发人员通过使用异步web请求和客户端MVC提高了基于web的应用程序的交互性,因此发送到服务器的请求是非阻塞的,并且在没有应答的情况下继续执行。但是,随着web应用程序的功能越来越像桌面应用程序,等待任何客户机/服务器交互都会让应用程序感觉迟钝或崩溃。这就是我们的下一个救援模式。
    在考虑应该在何处实现业务逻辑时,您会发现客户端MVC模式具有很好的灵活性。在图1.1中,为了简单起见,我们在模型中合并了业务逻辑,但它也可能存在于应用程序的其他层中,包括控制器。自从1979年trygvereenskag为Smalltalk-76引入MVC模式以来,MVC模式已经发生了变化。
    考虑验证用户提供的邮政编码:
    • 视图可能包含JavaScript,在输入或提交之前验证邮政编码。
    • 当模型创建一个地址对象以保存传入数据时,该模型可能会验证邮政编码。
    • ZIP代码字段上的数据库约束可能意味着模型也在强制执行业务逻辑,尽管这可能被认为是一种不好的做法。
    很难定义什么构成了实际的业务逻辑,在许多情况下,前面的所有约束都可能在单个请求中起作用。
    在本书中构建应用程序时,我们将研究如何以及在何处组织业务逻辑,以及Vue及其支持库如何帮助防止功能跨过边界。
     
    1.1.2. Model–View–ViewModel模式(MVVM)
     
    当JavaScript框架开始支持异步编程技术时,web应用程序不再需要请求完整的web页面。通过对视图进行部分更新,网站和应用程序可以更快地做出响应,但这样做需要一定程度的重复工作。表示逻辑通常反映了业务逻辑。
     
    MVC的一种改进,Model-View-ViewModel(MVVM)模式的主要区别是引入了视图模型及其数据绑定(统称为binder)。MVVM为我们构建客户端应用程序提供了一个蓝图,该应用程序具有更灵敏的用户交互和反馈,同时避免了整个体系结构中代价高昂的代码重复和工作。单元测试也更容易。也就是说,MVVM对于简单的UI来说可能过于致命了,所以要考虑到这一点。
     
    对于web应用程序,MVVM的设计允许我们编写能够立即响应用户交互的软件,并允许用户自由地从一个任务移动到下一个任务。如图1.2所示,视图模型也戴着不同的帽子。这种责任的整合对我们的应用程序的视图有一个单一而深刻的含义:当视图模型中的数据发生变化时,绑定到它的任何视图都会自动更新。数据绑定器公开数据并帮助确保当数据更改时,它会反映在视图中。
    您可以在martinfowler的页面上找到关于MVVM模式的更多信息https://martinfowler.com/eaaDev/PresentationModel.html。
    MVC和MVVM的区别:link
    1.1.3. 什么是reactive应用程序?
     
    反应式编程范式并不一定是一个新的想法。但是web应用程序对它的采用相对较新,这在很大程度上要归功于JavaScript框架的可用性,如Vue、React和Angular。
     
    网上有很多关于reactive的资源,但我们的需求可能更集中一些。要使web应用程序被认为是reactive的,它应该执行以下操作:
    • 观察应用状态的变化
    • 在整个应用程序中传播更改通知
    • 根据状态更改自动渲染视图
    • 为用户交互提供及时反馈

    反应式web应用程序通过采用MVVM设计原则来实现这些目标,MVVM设计原则使用异步技术来避免阻塞持续的交互,并在可能的情况下使用函数式编程习惯用法。

    尽管MVVM模式并不意味着一个反应式应用程序,反之亦然,但它们有一个共同的意图:为应用程序的用户提供一个更具响应性、更可靠的体验。超人和克拉克肯特可能会以不同的方式展现自己,但他们都想为人类做正确的事。(不,我不会说MVVM和Reactive中的哪一个穿斗篷,哪一个戴眼镜。)
    如果您想了解更多关于Vue的反应性编程范式的信息,请查看下面的“反应性深入指南”https://vuejs.org/v2/guide/reactive.html。
     
    1.1.4. 一个JavaScript计算器
     
    为了更好地理解数据绑定和反应性的概念,我们将首先用普通的JavaScript实现一个计算器,如下清单所示。
    Listing 1.1. The JavaScript calculator: chapter-01/calculator.html
    无。

    1窗体输入以收集绑定到runCalc函数的x和y
    2显示x和y的结果
    3显示了创建计算实例的构造函数
    4显示了为calc实例创建值的构造函数
    5初始化计算组件
    6显示事件处理程序
    7在keyup上设置事件侦听器

     

     

    这是一个使用ES5JavaScript的计算器(我们将在本书后面使用更现代的JavaScriptES6/2015版本)。我们使用一个立即调用的函数表达式来启动JavaScript。构造函数用于保存值,handleCalcEvent事件处理程序在任何keyup上激发。

    1.1.5. 一个Vue计算器
     
    不要太担心Vue示例的语法,因为我们这里的目标不是理解代码中的所有内容,而是比较两个实现。也就是说,如果您对JavaScript示例的工作原理有很好的了解(如下面的清单所示),那么大部分Vue代码至少在理论上应该是有意义的。
    Listing 1.2. The Vue calculator: chapter-01/calculatorvue.html
    无。

    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标记,然后创建应用程序运行所需的所有数据和事件绑定。

    1.1.7. Vue如何实现MVVM和反应性?
     
    Vue有时被称为一个渐进式的框架,这意味着它可以被合并到一个现有的web页面中以完成简单的任务,或者完全可以作为一个大型web应用程序的基础。
    无论您选择如何将Vue合并到项目中,每个Vue应用程序都至少有一个Vue实例。最基本的应用程序将有一个实例,它提供指定标记和存储在视图模型中的数据之间的绑定(见图1.4)。
    图1.4:典型的Vue实例通过在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还支持通过继承扩展组件,将功能与mix­ins结合,并通过插件和自定义指令扩展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为你的下一个项目。

    第二章:Vue实例
    本章介绍:
    如何创建一个Vue实例
    观察Vue生命周期
    向Vue实例添加数据
    将数据绑定到标签
    输出格式化
     
    在本书的整个过程中,我们将构建一个完整的web应用程序:一个包含产品列表的webstore、一个签出过程、一个管理界面等等。完成的webstore看起来可能还有很长的路要走,特别是如果您是web应用程序开发的新手,但是Vue允许您从小处着手,在所学的基础上进行构建,并在一个平稳的过程中发布一个复杂的产品。
    在一个应用成长的每一个阶段Vue保持一致性的关键是Vue实例。一个Vue应用是一个Vue实例,Vue组件是所有的Vue实例,而你甚至可以使用你自己的自定义属性通过创建实例可以扩展Vue。
    在一章中不可能触及VUE实例的所有方面,所以我们将建立在我们的应用程序演化的基础上。当我们在接下来的章节中探索新特性时,我们通常会在本章中提到我们对Vue实例和Vue生命周期的了解。
     
    2.1. 我们的第一个应用
     
    为了开始我们的旅程,我们将创建WebStury应用程序的基础,显示它的名称,并创建单个产品列表。我们的重点是如何创建Vue应用程序,以及视图模型中的数据与视图中数据显示的关系。图2.1显示了本章结束时我们的应用程序应该是什么样子。
    图2.1:我们简陋的网店开始的预展。 

    如果您尝试了清单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代码包含在chapter­02文件夹中的文件。(如果您还没有下载本章附带的代码,请在附录A中了解如何以及在何处获得它。)让我们创建第一个Vue应用程序。

    Listing 2.1. Our first Vue application: chapter-02/first-vue.html

    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>.....什么也没有(或者可能是关于下载vue­devtools的注释,如果您还没有这样做,或者是在开发模式下运行vue的注释)。图2.2显示了控制台的外观。

    Figure 2.2. The JavaScript console with no errors or warnings.

    即使到目前为止我们的应用程序很简单,但当我们在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属性。在以后的章节中,我们将使用控制台访问实例,以便在应用程序运行时调试、操作数据和触发应用程序中的行为,这样我们就可以验证它的行为是否符合预期。我们还可以使用vue­devtools在应用程序运行时查看其内部。(同样,如果您还没有安装vue­devtools,请访问附录A了解如何安装它。)让我们看看它与使用JavaScript控制台的比较。图2.4显示了vue­devtools的不同部分。

    Figure 2.4. The vue-devtools window with nothing selected.
    vue­devtools扩展为检查vue应用程序、其数据及其组件之间的关系提供了强大的功能。随着应用程序复杂性的增长,vue­devtools中的可搜索树视图以JavaScript控制台无法做到的方式显示组件之间的关系。我们将在后面的一章中详细讨论Vue组件以及它们与Vue实例的关系。
    在构建应用程序时,我们将经常使用这两种工具来关注应用程序的问题。事实上,我们可以使用vue­devtools来发现另一种在JavaScript控制台中访问应用程序实例的方法,如图2.5所示。
    Figure 2.5. The root instance selected in vue-devtools with a variable dynamically assigned to the instance.

    当您在树状视图中选择一个实例时,如图2.5所示,vue­devtools将实例的引用分配给$vm0变量。我们可以像使用webstore变量一样使用$vm0。尝试在JavaScript控制台中使用$vm0,看看是否可以检查根Vue实例。

    为什么我们需要不止一个参考呢?

    使用多种方法访问同一实例可能显得多余,但同时使用这两种方法会有所帮助。

    当我们将根Vue实例分配给全局变量webstore时,我们为自己提供了一种在页面上的其他JavaScript代码中引用应用程序的方法。这样做允许我们与其他库、框架或我们自己的代码集成,这些代码可能需要引用回我们的应用程序。

    分配给$vm0变量的Vue实例反映了在Vue­devtools中所做的当前选择。当一个应用程序由数百个,甚至数千个实例组成时,以声明方式分配每个实例是不实际的,因此在检查和调试这样一个复杂的应用程序时,访问以编程方式创建的特定实例的方法是必不可少的。

    2.1.3 在我们的视图中显示些什么
    到目前为止,我们的应用程序还真是无聊。让我们通过在应用程序模板中显示来自应用程序实例的数据来激活它。请记住,我们的Vue实例使用我们提供的DOM元素作为其模板的基础。
     
    我们将首先添加我们的网站商店的名称。这将向我们展示如何将数据传递到Vue构造函数,以及如何将数据绑定到视图。在这个清单中,让我们更新清单2.1中的应用程序代码。
    Listing 2.2. Adding data and a data binding: chapter-02/data-binding.html

    1将头元素添加到div。
    2显示sitename属性的数据绑定
    3将数据对象添加到Vue选项
    4显示了我们在标头中绑定到的sitename属性

    我们在传递到Vue构造函数的选项中添加了一个数据对象。该数据对象包含一个属性sitename,它包含我们的webstore的名称。

    我们的站点名称需要一个home,因此我们还向应用程序根div元素内的标记添加了一个header元素。在标题元素<h1>上,我们使用数据绑定元素指令v­text=“sitename”。

    v­text指令打印它引用的属性的字符串表示形式。在这种情况下,一旦我们的应用程序启动并运行,我们应该看到一个带有文本的标题“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定义的样式。

    Figure 2.6. Our sitename property displayed in the header of our webstore.

    在初始化应用程序时,Vue会自动为数据对象的每个属性创建getter和setter函数。这使我们能够检索实例的任何属性的当前值,或为其设置新值,而无需编写任何其他代码。要查看这些函数的运行情况,让我们首先使用getter打印sitename属性的值。

    如图2.7所示,sitename属性的getter和setter函数在应用程序实例的根级别公开。它允许我们从JavaScript控制台或与应用程序交互的任何其他JavaScript访问属性。

    Figure 2.7. Using the console and vue-devtools, we can check on our sitename property.
     
    当我们选择<root>实例时,还可以看到vue­devtools中列出的属性。现在让我们看看当我们在JavaScript控制台中使用setter设置sitename的值时,图2.8中发生了什么。
     
    Figure 2.8. Using Vue’s property getter and setter to print and update the sitename property, respectively
     
    一旦我们为sitename提供了一个新值并按Enter键,header元素中的输出就会自动更新。这是Vue的事件循环。让我们看看Vue的生命周期,看看对数据的更改如何以及何时触发对视图的更新。
     
    2.2. VUE生命周期
     
    当一个Vue应用程序第一次被实例化时,它就开始经历一系列事件,这些事件统称为Vue生命周期。尽管长时间运行的Vue应用程序可能会花费大部分时间在事件循环中循环,但库本身的大部分繁重工作都发生在应用程序第一次创建时。让我们从更高的层次来看图2.9中的生命周期。
    Figure 2.9. Diagram of the Vue lifecycle, divided into four phases.

    每个阶段都建立在上一阶段的基础上,以创建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在执行过程中到达代码的那一部分时,它就会调用您定义的函数,或者在无事可做的情况下继续执行。

    Listing 2.3. Adding lifecycle hooks to our instance: chapter-02/life-cycle-hooks.js
    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显示了如何做到这一点。

    Figure 2.11. Setting the sitename property triggers the update lifecycle callbacks.
     
    当您更改sitename属性时,更新周期将开始,因为应用程序头中的数据绑定将用新值更新。现在让我们销毁我们的应用程序!(别担心,它会很快重新加载回来)为了触发最后两个生命周期挂钩,我们使用实例的$destroy方法。
    Vue在我们的实例上创建的特殊方法可以使用$prefix。有关Vue生命周期实例方法的更多信息,请访问https://vuejs.org/v2/api/#Instance­Methods­Lifecycle
    这最后两个挂钩通常用于清理应用程序或组件中的活动。如果我们的应用程序创建了第三方库的实例,我们应该调用该库的teardown代码,或者手动分配对它的任何引用,这样我们就避免泄漏分配给应用程序的内存。图2.12显示了调用$destroy()实例方法将如何触发destroy钩子。
    Figure 2.12. Calling the destroy instance method triggers the final pair of lifecycle callbacks.
     
    2.2.3. 是否保留生命周期代码
    lifecyclehook提供了一种很好的方法来查看应用程序运行时的情况,但我首先承认,将消息记录到控制台需要重复的、冗长的代码。因为它们相当庞大,所以从现在开始我不会在代码列表中包含这些调试函数,但是我们偶尔会使用生命周期挂钩来探索新的行为,或者出于应用程序本身的功能原因。
     
    2.3. 展示产品
     
    显示webstore的名称是一个很好的开始,但是在继续之前,我们还应该讨论在标记中显示数据的一些方面。我们的网店将以以下几种方式之一显示产品:列表、网格、特色产品和单独的产品页面。在设计和标记每个视图时,我们将继续使用相同的数据但我们将使用Vue的功能对每个显示进行不同的操作,而不改变基础值或结构。
     
    2.3.1. 定义产品数据
    现在,我们只显示一个产品,所以让我们向数据对象添加一个示例产品。
    Listing 2.4. Adding product data to our Vue instance: chapter-02/product-data.js

    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)已经定义了所有列样式,因此我们只需要在标记中包含适当的类名。

    Listing 2.5. Adding product markup: chapter-02/product-markup.html

    1使用v-­bind指令将产品的图像路径绑定到img标签的src。

    2其他产品属性使用v­-text指令显示。

    您马上就会注意到的一件事是在数据绑定中使用JavaScript点表示法。因为产品是一个对象,所以我们必须为每个绑定提供指向属性的整个路径。我们的产品数据title、description和price的大多数属性都是使用v­text指令绑定的,就像我们在标题中绑定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#Using­JavaScript­Expressions

    让我们翻页到Chrome,重新加载页面,并确认产品信息显示为设计。

    Figure 2.13. Our product is displayed but has a few issues we need to clean up.
    Product description is not being interpreted as HTML.
    Price is not form atted.
    哦,我们还有几件事要做:
    1. 产品描述是作为字符串输出的,而不是解释嵌入在描述值中的HTML。
    2. 产品的价格显示为整数2000的字符串表示,而不是格式良好的美元数字。
    让我们先解决第一个问题。我们需要的是一个HTML指令,所以让我们使用v­-html绑定来更新产品标记,以便按预期输出产品描述。
     
    Listing 2.6. Adding product markup: chapter-02/product-markup-cont.html
     
    Figure 2.14. Using the v­html binding allows us to display the description as raw HTML.
     
    v­html绑定将把绑定属性呈现为原始html。这可能很方便,但应该谨慎使用,并且只有当值是您可以信任的值时。现在我们需要修正这个讨厌的价格值的显示。
     
    2.4 应用输出过滤器
     
    剩下要做的最后一件事是用熟悉的格式显示我们产品的价格,而不是原始整数。输出过滤器允许我们在值显示在标记中之前对其应用格式。输出过滤器的一般格式是{{property | filter}}。在我们的例子中,我们希望将产品的价格设置为20美元,而不是2000美元。
     
    2.4.1. 编写过滤函数
    输出过滤器是接收值、执行格式化任务和返回输出的格式化值的函数。当用作文本插值的一部分时,传递给过滤器的值就是我们绑定到的属性。
    我们所有的输出过滤器都驻留在传递给Vue实例的选项的filters对象中,因此我们将在下面的清单中添加价格格式化程序。
    Listing 2.7. Adding the formatPrice filter: chapter-02/format-price.js

    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样式绑定来应用过滤器,如下所示。筛选器不能与v­text绑定语法一起使用

     记住,带过滤器的绑定具有一般形式{property | filter},因此我们相应地更新了价格绑定{产品价格|格式价格}。回到Chrome,刷新,瞧,我们得到了一个格式化的价格,如图2.15所示。

    Figure 2.15. Our price formatter adds a dollar sign and the appropriate punctuation to the display of our price property’s value.

     如果我们在控制台中修改数据,我们可以看到过滤器是如何实时应用于不同的产品价格值的。要尝试不同的值,请打开控制台并设置产品价格用这样的语句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.

    练习
    利用本章的知识回答以下问题:
    在第2.4节中,我们为价格创建了一个过滤器。你能想出其他可能有用的过滤器吗?

    摘要
    Vue使您能够向应用程序添加交互性。
    在任何时候,我们都可以连接到Vue生命周期,以帮助执行某些功能。
    vue.js提供强大的过滤器,帮助以某种方式显示信息。

    【第二部分:视图和视图模型】

    这本书的重点在于视图和视图模型部分。这些章节将深入研究Vue以及构成Vue应用程序的所有元素和部分。我们将从简单开始,并为应用程序添加交互性。然后我们将讨论窗体和输入、条件和循环。

    一些最重要的概念在第6章和第7章中,我们将深入研究组件。这些确实是我们应用程序的构建块。这是第一章,我们将在这里看到单文件组件—您的系统中的一个强大工具vue.js工具带。

    最后两章将介绍转换、动画以及如何扩展Vue。这将使我们的应用程序更高效,看起来更漂亮。

    第3章:添加交互性

    本章涵盖:

    • 从具有计算属性的数据导出新输出
    • 向DOM添加事件绑定
    • 在Vue生命周期的更新部分观察数据
    • 响应用户交互
    • 有条件呈现标记

    信不信由你,现在我们已经把第一个产品都连接好了,我们已经准备好为我们的网站商店添加交互了。

    向应用程序添加交互性意味着绑定到DOM事件,在应用程序代码中响应它们,并向用户提供关于由于其操作而发生的事情的反馈。Vue为我们创建和管理所有事件和数据绑定,但是我们需要做出一些决定,即如何在应用程序中操作数据,以及如何在界面中满足用户期望。

    我们将开始探索用户交互,让客户将我们的单个产品添加到购物车中,但在此过程中,我们还将研究如何将我们的工作融入Vue应用程序的整体图景。

    为了了解我们在本章中的发展方向,图3.1显示了在完成所有工作后应用程序的外观。

    Figure 3.1. Our product listing with new elements: a shopping cart and an Add to cart button.

    3.1. 购物车数据从添加数组开始

    在构建任何超级酷购物车功能之前,我们需要一个容器来存放应用程序实例中的所有项目。幸运的是,在这个阶段我们只需要一个简单的数组,我们将把产品推到这个数组上。

    我把代码分解成小片段,类似于我们在上一章中所做的那样。你需要把这些添加到你的index.html您创建上一章以继续应用程序的文件。如果需要,您可以始终下载本章的代码。

    Listing 3.1. All we need is an array: chapter-03/add-array.js

    1显示我们现有的产品数据,供参考
    2显示了一个用于存放购物车项目的数组

    我们的购物车。完成。不过,认真地说,我们将从这个简单的数组中获得很好的效果,但最终我们将创建一个cart组件,该组件将在内部管理其内容。

    3.2. 绑定到DOM事件

    为了向应用程序添加交互,我们需要将DOM元素绑定到在Vue实例中定义的函数。我们可以使用事件绑定将元素绑定到任何标准的DOM事件click、mouseup、keyup等。Vue负责引擎盖下的所有布线,因此我们可以关注应用程序在事件发生时如何响应。

     
    3.2.1. 事件绑定基础知识
    事件绑定使用v­-on指令将JavaScript片段或函数绑定到DOM元素,如图3.2所示。当触发指定的DOM事件时,将执行绑定的代码或函数。
    Figure 3.2. The syntax of an event binding

     以下是事件绑定的JavaScript的两种常见模式:

    1. 使用函数名,我们可以将事件绑定到实例中定义的函数。如果我们有一个绑定,比如v­on:click=“clickHappened”,那么单击元素就会调用函数clickHappend。

    2. 我们可以编写作用于公开属性的内联JavaScript。在本例中,绑定可能看起来像v-­on:keyup=“charactersRemaining-­=1”,这会将charactersRemaining属性减少1。

    每个策略在应用程序中都有自己的位置,但首先我们要看看如何使用函数来处理事件。

    请注意,有一种更简单的简写方法来编写v-­on指令。你可以用@符号代替v-­on。例如,如果你想使用v­-on:click=“…”你可以用@click=“…”代替它。我们稍后会在书中用这个速记法。

    3.2.2. 将事件绑定到“添加到购物车”按钮
    客户需要一个按钮才能将产品添加到购物车中。我们将指示Vue将该按钮的click事件绑定到处理将产品推送到购物车数组的函数。
    在将按钮添加到标记之前,应该先编写函数。为此,我们需要向应用程序的选项中添加一个methods对象。在filters对象之后,添加以下代码。(不要忘记在filters对象后面加一个逗号!)
    Listing 3.2. The addToCart method: chapter-03/add-to-cart.js

    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中的价格加价之后,添加这个列表中的按钮。

    Listing 3.3. A button to add products to the cart: chapter-03/button-product.js
    1 显示我们的Add to cart按钮
    2 将按钮的click事件绑定到addToCart函数
    现在,当访问者单击此按钮时,将调用addToCart函数。是时候试一试了。
    转到Chrome,确保控制台是打开的,然后切换到Vue选项卡,因为我们想查看添加到购物车中的数据。cart数组应该是空的,因此如果您没有看到如图3.3所示的数组[0],请继续并重新加载页面。
    Figure 3.3. An empty array is what we should see before any products are added. If it’s not empty, go ahead and reload the page.

     现在,单击addtocart按钮几次。打开vue­-devtools窗格并单击<Root>。您应该看到每次单击都会将产品的id推送到阵列上,如图3.4所示。

     

     使用vue­-devtools或控制台查看购物车中有多少项目对开发人员来说可能没问题,但是客户需要视图本身的反馈。是时候添加项目计数器了。

    3.3. 添加购物车项目按钮和计数
     
    要显示客户在购物车中拥有的商品数量,我们将使用计算属性。计算属性可以像实例定义的任何其他属性一样绑定到DOM,但是它们通常提供从应用程序的当前状态派生新信息的功能。此外,我们将添加一个购物车项目按钮,它将显示我们的结帐购物车。
    在向购物车添加商品计数之前,让我们更全面地了解计算属性及其工作方式
     
    3.3.1. 何时使用计算属性
    将数据对象中的属性视为表示存储在数据库中的数据,将计算的属性computed视为主要在视图上下文中使用的动态值,这可能会有所帮助。这可能是一个过于宽泛的描述,但它是一个很好的第一条经验法则。
    让我们考虑一个显示用户全名的computed属性的常见示例,如清单3.4所示。将某人的名字和姓氏存储为数据库中的独立实体是有意义的,但是它是冗余的,而且也容易出错,也会存储他们的全名。如果出现显示用户全名的需要,那么结合现有数据中的第一个和最后一个名称是计算属性的一个完美用例。
    Listing 3.4. Computing a user’s full name: chapter-03/computed.js

     1 fullName返回用户的名字和姓氏的值,由单个空格连接。

    fullName函数返回的结果在概念上等同于在数据对象中具有fullName属性,这意味着我们可以轻松地绑定到标记中(见图3.5)。

    Figure 3.5. Combining the user’s first and last name from a dataset into a full name for display.

     使用计算属性的另一个好处是,我们可以更改函数的内部结构,以使用来自应用程序的不同或附加数据。例如,在图3.5中,我们可以使用prefix属性为用户的全名添加更多的形式。

    以这种方式使用计算属性,我们可以组合或以其他方式操纵任何实例数据,而无需更改后端或数据库。

    3.3.2. 检查具有计算属性的更新事件

    因为计算属性通常是使用实例数据计算的,所以当基础数据更改时,它们的返回值会自动更新。因此,绑定到computed属性的任何视图标记都将更新以反映新值。

    在更大的Vue实例生命周期中,此行为是更新周期的核心。为了了解更新周期的行为,让我们通过另一个示例来了解计算属性何时最适合该作业。考虑根据矩形的长度和宽度计算矩形面积的任务。

    Listing 3.5. Computing the area of a rectangle: chapter-03/computed-rect.js

    1显示包含长度和宽度属性的数据对象
    2显示一个计算属性,该属性公开的区域与数据属性相同

    计算的物业面积的初始值为15。对长度或宽度的任何后续更改都会触发对应用程序的一系列更新:

    1. 当长度或宽度的值改变时。
    2. . . . 重新计算计算的属性区域。
    3. . . . 然后将更新绑定到这些属性的任何标记。

    图3.6显示了应用程序的更新周期。

    Figure 3.6. Changes in an instance’s data trigger a cascade of activity within the update cycle of an application.

    通过使用watch函数观察实例中的数据何时发生更改,以及beforeUpdate lifecycle钩子(应该只在数据发生更改后执行),我们可以看到生命周期的运行情况。

    watch函数的工作方式与lifecycle钩子相同,但当它“监视”的数据更新时会触发。我们甚至可以创建一个watch函数来观察计算的属性。

    清单3.6将面积计算放在一个完整应用程序的上下文中。该应用程序还包含三个监视函数,在长度、宽度或区域发生变化时将消息记录到控制台,以及一个在更新周期开始时记录消息的函数。必须在Vue实例的watch选项中指定这些函数才能工作。

    Listing 3.6. Computed properties and update event logging: chapter-03/area.html

     

    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对象,这样我们的函数就有了生存的空间。

    Listing 3.7. The cartItemCount’s computed property: chapter-03/cart-item-count.js

    1添加计算对象
    2返回购物车数组中的项目计数

    这是计算属性的简单用法。我们使用数组的现有JavaScript属性长度来检索计数,因为实际上不需要为购物车添加我们自己的计数机制。

    这也是一个很好的例子,说明为什么不适合将此类数据存储为数据对象的属性。因为cartItemCount的值是用户交互的结果,而不是来自数据库的结果,所以我们不希望在数据对象中看到它。

    值得注意的是,有时这样的项计数可能在数据对象中。例如,如果用户正在查看“以前的订单”页面,则可能存在与每个订单相关联的项目计数。这与我们到目前为止的想法是一致的,因为在处理和持久化订单之后,数据将来自数据库。

    功能到位,我们准备在应用程序的头上添加一点HTML,这样我们就可以有购物车和一个显示项目计数的地方。更新标题中的标记,如此处所示。

    Listing 3.8. Adding the cart indicator: chapter-03/cart-indicator.html

    1将我们的购物车向右对齐
    2显示计算属性的数据绑定

    我们向头添加了一个新的div元素,这样我们就有了一个放置cart的位置,并且我们使用cartItemCount绑定来显示computed属性的值。绑定被一个span元素包围,这个元素用作样式挂钩,在我们的计数器旁边添加一个cart图标。是时候测试一下了。

    在Chrome中重新加载webstore应用程序后,单击addtocart应该会导致指示器随着每次单击而增加。您可以通过再次检查控制台中的cart数组来再次检查计数是否正确(参见图3.11)。

    3.4. 为我们的按钮添加用户可承受性

    当人们到达一个网站或使用一个web应用程序时,他们带来了各种各样的体验和期望。其中一个最基本的、根深蒂固的问题是,当交互元素的行为与预期不同时,产品可能会感到支离破碎或迷失方向。用户可承受性背后的思想是向用户提供视觉(或其他)提示和反馈,以使我们的应用程序与他们的期望保持一致。

    我们现在有一个按钮,让客户无休止地添加一个产品到他们的购物车。限制顾客可以购买的商品数量可能有很多原因:有限的可用产品、对每位顾客购买的限制、数量折扣等等。如果数量有限,则“添加到购物车”按钮应在某个点不可用,或者以其他方式指示该操作不再可能。

    为了完成这项任务,我们需要跟踪可用的库存,将其与购物车中的产品实例数量进行比较,并采取措施防止客户添加的产品数量超过可用的数量。让我们从跟踪库存开始。

    3.4.1. 关注库存

    为了防止客户购买过多的给定产品,我们需要向product对象添加一个新属性,如下面的清单所示。availableInventory属性将表示我们商店有多少个单独的产品单位可用。

    Listing 3.9. Adding availableInventory to our product: chapter-03/available-inventory.js

     如果另一个客户在交易过程中购买了一个或多个相同的产品,那么在完成购买时仍有必要再次检查产品的可用性,但我们可以在应用程序中实现一个简单的解决方案,以大大减少用户稍后因隐藏或禁用而失望的机会,添加到购物车按钮。

    3.4.2. 使用计算属性和库存

    我们不想改变availableInventory值,因为它表示一个固定值,该值只能由一个管理实际库存的过程来更新(这一点我们将在本书的稍后部分进行讨论)。但我们确实希望根据可用投资的价值来限制客户可以添加到购物车中的产品数量。

    要做到这一点,我们需要一种方法来跟踪客户购物车中相对于固定数量的可用产品的商品数量。我们将使用computed属性实时执行此计算,因为客户将商品添加到他们的购物车中。

    Listing 3.10. A computed property for remaining inventory: chapter-03/computed-remaining.js

    1使用canAddToCart计算属性
    2将可用库存与购物车中已有的物品数量进行比较

    因为我们的代码可以以与实例数据属性相同的方式使用计算属性,所以我们有机会在另一个计算属性中利用一个计算属性cartItemCount。我们的新计算属性检查可用库存是否大于购物车中已有的商品数量。如果没有,这意味着客户已经将最多数量的产品添加到他们的购物车中,我们将不得不采取行动阻止他们添加更多的产品。

    JavaScript中的“真实性”

    您可能已经意识到,在JavaScript中计算表达式的真值可能有点棘手。下面是一个简单的例子,你可以自己在控制台中尝试。

    当使用非严格相等运算符==时,与字符串值“1”相比的整数值1的计算结果为true。之所以会出现这种情况,是因为JavaScript试图“提供帮助”,在计算比较之前进行类型转换。使用严格相等运算符===会产生预期的错误结果。

    在canAddToCart函数中,我们使用大于运算符>来比较两个整数值。如果我们对这些值的来源有任何疑问,或者它们实际上是整数,我们可以使用parseInt方法强制转换,或者确保这些值是整数。

    3.4.3. v-show指令基础
    现在我们有了一个机制来确定客户是否可以执行addtocart操作,让我们让接口相应地响应。当且仅当指定条件的计算结果为true时,v­show指令才会呈现标记。如果canAddToCart属性返回false,则将其添加到现有按钮会导致该按钮从DOM中隐藏,如下所示。
    Listing 3.11. Button with v­-show directive: chapter-03/button-v-show.html

    1 v-­show指令绑定到我们的canAddToCart计算属性。

    如果您在Chrome中重新加载应用程序并尝试向您的购物车中添加六种产品,则在第五次单击时按钮应该消失,因为这是availableInventory的值,如图3.12所示。

    Figure 3.12. The Add to cart button is hidden when we exhaust the available inventory.
     
    v­show指令的工作方式与我们迄今为止遇到的其他指令有点不同。当表达式的计算结果为false时,Vue将元素的DisplayCSS属性设置为none作为内联样式。这有效地隐藏了元素(及其内容)不受视图的影响,尽管它仍然存在于DOM中。如果表达式的结果后来更改为true,则将删除内联样式,并且元素将再次显示给用户。
    注意,这种行为的一个副作用是,您所做的任何内联显示声明都将被覆盖。但是不用担心,Vue在移除自己的值时会恢复原来的值显示:无。不过,最好避免在可能的情况下使用内联样式,而不是样式表中的类定义。
    要记住的另一件事是,v-­show指令在绑定到单个元素而不是几个相邻元素时最有效。下面是一个例子。
    Listing 3.12. Wrapping content for v­show: chapter-03/wrap-content.html

    1 避免在相邻元素上使用v-­show指令。
    2 取而代之的是,包装相邻的元素,并使用单个v-­show指令。

    要清楚的是,在应用程序中使用v­show是可以的。只要有可能,最好将对数据作出反应的多个元素聚合在一起,这样既可以获得更好的性能,又可以减少在进行更改时忘记更新所有元素的机会。当库存耗尽时删除addtocart按钮当然可以,但这有点过分。我们换个方法试试。

    3.4.4. 使用v-if和v-else显示禁用的按钮

    删除addtocart按钮当然可以防止客户向cart添加太多的产品实例,但这有点太过繁重了。对用户来说,禁用按钮可能更有用,因为这样不会破坏界面的连续性,并且可以保留布局流。

    v-­if和v-­else指令用于根据所提供表达式的真值显示两个选项之一。我们将使用canAddToCart作为评估的条件,就像我们在前面的示例中所做的那样。

    在图3.13中,您可以看到v-­if指令是如何工作的。如果canAddToCart为true,则会显示按钮,否则不会显示按钮。

    Figure 3.13. Diagram explaining how the v-­if directive conditional works.

    在这个清单中,我们可以看到这是如何处理我们的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标记相邻,如图所示。

    Listing 3.14. Single container elements for v­if and v­else chapter-03/single-container.html

    1 如果v­if和v­else被第二段元素分解,这就行不通了。

    2 如果v­if和v­else在标记中不相邻,则这将不起作用。

    3 这将工作;在元素中包装相关内容,然后将v­if和v­else绑定到该元素。

    这里的目标是将给定条件的所有DOM元素保留在用作分组容器的外部元素中。稍后,我们将探讨使用模板或组件隔离条件标记的不同策略,从而大大简化主应用程序本身所需的标记量。

    3.4.5. 将购物车项目按钮添加为切换

    让我们为结帐页面添加一个按钮。我们将首先向应用程序添加一个新方法和属性。

    Listing 3.15. Adding the cart button: chapter-03/cart-button.js

    1此属性跟踪是否显示产品页。
    2单击购物车按钮后会触发showCheckout方法。
    3显示在真与假之间切换的三元运算

    新的showProduct属性将切换签出页的显示。让我们更详细地看一下。showCheckout方法通过在JavaScript中使用称为三元操作的操作来切换showProduct属性。三元运算符是if语句的快捷方式,它有三个参数。第一个参数是条件,在这种情况下,此.showProduct. 如果解析为true,则返回第一个表达式false。否则返回最后一个表达式true。当您需要创建一个快速的条件语句时,三元条件运算符是一个非常有用的工具。

    您可能已经注意到方法定义在showCheckout()之后缺少function()声明。ES6(也称为ES2015)允许使用较短的方法定义语法。在本书的其余部分中,我们将在方法定义中使用这种语法。

    我们现在需要将按钮添加到视图中,并将其绑定到click事件:

    Listing 3.16. Adding the cart button: chapter-03/add-cart-button.html
    1添加到按钮的单击事件触发showCheckout方法。
    单击该按钮时,showCheckout方法将激发,从而导致showProduct方法在状态之间切换或翻转。“签出Check”按钮很重要,因为我们需要在某个地方放置签出Check信息。我们将在下一节中详细介绍。
     
    3.4.6. 使用v-if显示签出Check页面
    我们的应用是有限的。它只在一页上显示一个产品。为了使其更完整,我们需要另一个显示签出Check信息的页面。我们可以用很多不同的方法来做。在第7章中,我们将了解组件,这些组件可以让我们轻松地将应用程序分解为更小的可重用部分。这可能是添加签出Check页面的一种方式。
    另一种方法是用v-­if指令包装我们的视图,并将其绑定到我们之前创建的showProduct属性。我们需要在main和div元素之后的索引文件顶部添加v-­if指令,如清单所示。
    Listing 3.17. Using v­if to display a checkout page: chapter-03/v-if- checkout.html

    1 v­if指令,如果showProduct为true,则显示该指令。
    2显示视图的产品列表,包括产品的图片和说明
    3这是结帐页面的位置。

    在本章前面,我们创建了一个checkout按钮。按下此按钮时,showProduct属性将从true切换到false,或从false切换到true。这将触发清单3.17中的v-­if指令。我们在本章中创建的产品信息将显示出来,或者只显示顶部导航的空白屏幕(图3.15)。

    Figure 3.15. View of webstore after checkout button is pressed. Pressing the checkout button again shows the product page.

     现在,不要担心我们在图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是正确的选择:

    • 一个信息横幅的东西是暂时的,如一个销售公告或条款和条件的变化。
    • 一个注册广告,或其他诱因,当一个访问者没有登录。
    • 跨多个页面运行的列表的分页元素,如果只有一个页面,这将是多余的。

    当呈现两个标记块中的一个时,v­if和v­else指令是正确的选择,但至少应该始终显示其中一个。如果没有回退(else)情况,那么v­show更合适。这里有几个应该使用v­if和v­else的场景:

    • 显示已注销用户的登录链接,而显示已登录用户的注销链接。
    • 根据用户所做的选择呈现表单的条件部分,例如特定于国家的地址字段。例如,美国地址表显示“州”字段,加拿大地址表将其显示为“省”
    • 未进行搜索时,搜索结果列表与占位符内容。(在后面的一章中,我们将探讨使用v­else­if添加第三状态的示例。)

    无休止的场景存在,你需要使用一个或另一个条件。考虑哪一个适合您的需要的最佳方法可能是考虑是否有要显示的内容块的回退或默认值。接下来,我们将通过提供不止一袋猫粮,让我们的网络商店对潜在客户更加有用。

     
    练习
    利用本章的知识回答以下问题:
    在本章的前面,我们讨论了计算属性和方法。它们之间有什么区别?
     
    第4章 表格和输入
    本章涵盖
    • 将值绑定到DOM
    • 使用文本绑定
    • 修饰语

    我们的应用程序从第一章开始有了实质性的发展。我们已经创建了项目,并允许用户将项目添加到购物车。我们现在需要一种方式让我们的客户签出并输入他们的信息。让我们将输入表单添加到我们的应用程序中,以便客户可以在应用程序中输入他们的地址和帐单信息。然后我们需要将这些信息保存在我们的应用程序中以供以后使用。

    为了实现我们的目标,我们必须在应用程序中将表单数据绑定到我们的模型。v­-model指令就是为这个用例设计的。

    定义:v-­model指令在表单或文本区域输入和模板之间创建双向数据绑定。这确保了我们的应用程序模型中的数据始终与我们的UI保持同步。

    双向数据绑定与单向数据绑定

    在实践中,双向数据绑定(图4.1)可能是最好的解决方案,也可能不是。在某些情况下,从用户输入捕获数据后,数据将不需要更改。其他框架和库,如React和Angle2默认情况下选择了单向数据绑定。Angle1从双向绑定开始,在构建Angle2时出于性能管理原因放弃了它。单向数据绑定y历史主题学习路径提供&amp;交易突出显示当输入更改时捕获的数据未从模型同步到视图时支持签出的设置。需要添加额外的逻辑,以便在模型或视图中更改值。余烬.js默认情况下,决定坚持双向数据绑定。使用v­模型指令,数据绑定有两种方式。不管怎样,我们都可以使用v­once指令将属性指定为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/#v­once。

    在本书的后面,我们将讨论组件属性以及如何将它们传递给其他组件。这些属性在父属性和子属性之间形成单向绑定。这将在将来变得有用。

    v­-model指令用于各种表单输入,包括文本框、文本区域、复选框、单选按钮和选择下拉控件。我们需要所有这些元素来构建新的签出checkout表单。让我们看看如何使用v­-model指令,以及它如何处理绑定输入。

    4.1. 使用V-MODEL绑定
    应用程序中的模型绑定将帮助我们用模板更新用户输入的数据。在我们的应用程序中,我们主要使用Vue数据对象来显示静态信息。与应用程序的交互仅限于几个按钮点击事件。我们需要为用户添加一种在结账时填写发货信息的方法。为了跟踪表单输入,我们将使用v­model指令和基本输入绑定为应用程序添加更多反应性。
    在我们开始之前,您可能想知道在第2章中使用的v-model指令和v-bind指令之间有什么区别。请记住,v­model指令主要用于输入和表单绑定。在本章中,我们将使用v­model指令为签出页面绑定文本输入。v­bind指令主要用于绑定HTML属性。例如,我们可以在<img>标记的src属性上使用v­bind,或者将其绑定到<div>标记的class属性上。两者都很有用,但它们在不同的情况下使用。我们将在本章后面更详细地研究v­bind指令。
    值得一提的是,v­model指令在幕后使用v­bind指令。假设你有<input v­model=“something”>。v­model指令是<input v­bind:“something”v­on:input=“something”的语法糖=$event.target.value事件目标值">. 无论如何,使用v­model指令更容易输入和理解。
    在图4.2中,我们看到了v-model指令是如何被分解的。它被添加到输入中,并创建一个双向数据绑定对象。
    Figure 4.2. Up close with the v-­model directive

    首先,我们需要在应用程序中添加新的HTML。打开index.html您在上两章中创建的页面,并查找v­else指令(或者您可以下载提供的index.html第3章的文件)。在这个<div>标记中,我们将在本章中添加HTML代码。在第7章中,我们将讨论将应用程序分解为组件的更好方法。现在,我们将使用简单的v­if指令作为切换来显示签出页面。

    与前几章一样,每个代码段都被拆分为自己的文件。请把这个和这个结合起来index.html创建已完成的应用程序。

    Listing 4.1. A v­model directive with first and last name inputs: chapter-04/first- last.html

    1.firstName和lastName使用v­model绑定。
    2.随着输入值的变化,firstName和lastName属性将实时显示。

    代码为名字和姓氏创建两个文本框,每个文本框绑定到实时同步的属性。这些属性是在数据对象中创建的。为了简化这个过程,我们将使用order属性将这些值保存在Vue实例数据对象中。这将添加到index.html文件。

    在数据对象中,我们需要添加新的order属性。我们需要这个order属性,这样就可以跟踪名字和姓氏。将以下代码添加到现有的索引.html我们在上一章中使用的数据对象。

    Listing 4.2. The Vue instance data object order property: chapter-04/data-property.js

    此列表中的order对象位于Vue构造函数内的数据对象中。我们可以使用第2章中学习的双花括号Mustache语法{{}}在整个代码中引用这个对象。例如{{订单名}}将替换为order对象中的名字。将我们的订单信息保存在一个对象中可以更容易地理解数据在将来的位置。

    值得一提的是,我们可以在这里使用空的order对象,而不是在其中显式定义firstName和lastName属性。vue.js可以隐式地将属性添加到对象。为了简单起见,为了让代码库更干净一点,我们将添加属性,这样我们就可以看到一切是如何工作的。

    在我们的checkout表单中输入数据之后,注意值实时出现在框中(图4.3)。这就是双向数据绑定的美妙之处。值之间自动同步,无需任何其他逻辑。

    Figure 4.3. Text is updated in real time into the box at the bottom.

    我们现在有了结帐页面的开始。让我们将更多表单输入添加到index.html文件,以便我们的客户可以添加他们的地址信息,如下所示。我们可以在清单4.1中添加的HTML代码之后添加这个HTML。

    Listing 4.3. Adding in our other text inputs and select box: chapter-04/text-input.html

    您可能想知道,我们如何轻松地将更多状态添加到select下拉控件中。对于这个简单的例子,硬编码所有四个状态是好的。但是,如果我们要添加所有50个状态,我们可能需要动态生成选择框。在下一节中,我们将研究如何使用值绑定来帮助生成动态选项。

    在继续之前,不要忘记将新属性添加到Vue实例中的数据对象。

    Listing 4.4. Updating the Vue instance data object with new properties: chapter-04/data-new-properties.js

     如图4.3所示,如果这些属性中的任何一个在表单元素中发生了更改,那么这些值将在底部的<pre>标记中更新。重新加载浏览器,新表单应该如图4.4所示。

    Figure 4.4. Adding the address, city, state, and ZIP Code form fields into our checkout page.
    我们的表单checkout页面看起来不错,但我们需要添加更多的东西。让我们允许我们的客户选择作为礼物发货。为此,我们将添加一个简单的复选框。如果选中此复选框,我们将作为礼品发货。如果不是,则选定的项目将不会作为礼物发送。为了跟踪绑定,我们将使用order.gift属性。
    接下来,我们需要允许客户选择送货到家庭或公司地址。为此,让我们在代码中添加一个单选按钮。在Vue中,我们必须将两个复选框中的v­model指令设置为相同的值,否则单选按钮在单击后不会更新。
    最后,我们需要用order.method以及order.gift,如下表所示。在中的清单4.3之后添加这个HTML索引.html文件。
    Listing 4.5. Adding check boxes and radio buttons: chapter-04/adding-buttons.html

    1. Checkbox

    2. radio

    3. pre

    让我们通过添加以下代码将属性添加到数据对象。

    Listing 4.6. Adding more properties to our Vue data object: chapter-04/more-props.js

    您可能注意到我们为方法和礼物添加了默认值。这背后的原因很简单。默认情况下,选择“方法”单选按钮,并且未选中复选框。因此,我们现在在这个代码中设置默认值是明智的。

    最后一件事,我们需要做的是添加一个Place Order(提交)按钮。现在,我们将模拟按钮,以便将来使用它。有几种方法可以创建placeorder按钮。您可以将动作附加到包含所有输入的表单元素。(我们将在关于事件的第6章中进一步了解这一点。)相反,让我们使用我们在第3章中首先了解的v­on指令。v­on指令可以将函数绑定到应用程序中的DOM元素。将其添加到PlaceOrder按钮上的click事件。这个HTML代码可以在清单4.5之后添加。

    Listing 4.7. Adding the v­on directive to the click event: chapter-04/adding-v-on.html 

     在以后的章节中,我们将为placeorder按钮添加功能。出于我们现在的目的,让我们创建一个简单的函数,并通过添加一个警报弹出窗口来验证按钮是否有效。将submitForm函数添加到index.html文件,如清单所示。

    Listing 4.8. Creating the new submitForm method: chapter-04/submit.js

     在Vue构造函数中是methods对象,它保存了可以在应用程序中触发的所有函数。submitForm函数在触发时将显示一个警报弹出窗口。在浏览器中,单击PlaceOrder按钮,您将看到submitForm函数触发的弹出窗口(图4.5)。

    Figure 4.5. This popup was triggered by the submitForm function.

    现在我们已经有了一个placeorder按钮的表单,当它全部放在一起时,它应该像图4.6所示。

    Figure 4.6. Completed checkout page with all form elements included.
    表格中的每个属性都与我们的vue.js模型相连!现在让我们看看是否可以让我们的输入绑定更好一点。
     
    4.2. value绑定研究
    到目前为止,v模型指令在绑定属性方面已经很有用。我们用它绑定了许多基本输入。不过,我们有问题。如何绑定复选框、单选按钮和下拉控件的值?如果你还记得,我们会硬编码复选框和单选按钮的值。对于我们的选择框控件,我们将值留空。所有HTML元素都可以,有时也应该具有与所选选项关联的值。我们不要使用硬编码的值,而是重写我们的选择框、复选框和单选按钮,以使用数据对象中的属性。首先,我们使用v-bind指令更新我们的复选框,并使用值。
     
    4.2.1. 将值绑定到复选框
    在第一个示例中,我们的复选框绑定到order.gift属性。我们可以把它设为真或假。话虽如此,我们的客户不想看到真假。他们更希望看到一条信息,让他们知道订单是否会作为礼物发货。我们可以补充一下。
    v-­bind指令将值绑定到HTML元素中的属性。在本例中,我们将true­value属性绑定到一个属性。true­value属性对于v­bind指令是唯一的,它允许我们根据复选框是否被选中(true或false)来绑定属性。这将更改订单.礼品. 在清单4.9中,真值绑定到订单.sendGift财产。同样,false­值绑定到订单.dontSendGift财产。选中此复选框后,将显示订单.sendGift显示消息。如果未选中该复选框,则订单.dontSendGift属性显示。在中的清单4.8之后添加这个HTML index.html.
    Listing 4.9. Binding true and false values to the gift check box: chapter-04/true-false.html

    1.设置oder.sendGift属性
    2.设置order.dontSendGift属性
    3.绑定order.gift到输入input

    为了使这个绑定如我们所期望的那样工作,我们需要将这些新属性添加到order对象中,如下一个清单所示。更新中的order对象索引.htmlsendGift和dontSendGift属性的值。

    Listing 4.10. Adding the sendGift property to the order object: chapter-04/prop-gift.js

    1.复选框的默认值默认为“ Send As A Gift”复选框。
    2.order.sendGift属性是选中复选框时显示的文本消息。
    3.order.dontSendGift属性是未选中复选框时显示的文本消息。

    我们的数据对象越来越大了!如果选中或不选中复选框,我们现在可以指定文本值。刷新页面并取消选中“作为礼品发货”复选框。查看底部的框(图4.7);我们将看到{{订单.礼品}}属性。

    Figure 4.7. The {{order.gift}} property is displayed.

    4.2.2 使用值绑定和单选按钮

    像复选框一样,我们可以给单选按钮赋值。我们可以通过直接绑定值来实现这一点。这对于我们的应用程序来说可能是一个有用的特性。如果用户选择了home单选按钮,我们将向用户显示home address;如果用户选择business单选按钮,我们将向用户显示business address。将此HTML添加到索引.html在上一个复选框代码之后。

    Listing 4.11. Binding values to our radio buttons: chapter-04/radio-bind.html

    1. 将v­bind指令设置为第一个单选按钮的输入元素的value属性
    2. 将v­bind指令设置为第二个单选按钮的输入元素的value属性

    v-­bind指令绑定order.home到第一个单选按钮,order.business到第二个单选按钮。这可能很强大,因为我们可以随时动态更改这些值。

    为了完成这个示例,让我们将这些新属性添加到index.html,如下表所示。

    Listing 4.12. Updating the order object with business and home: chapter-04/update-order.html

    1. 默认值为Home Address

    2. 第一个单选按钮选中时显示order.business属性。

    3. 第二个单选按钮选中时显示order.home属性。

    这个新的order对象现在有几个新的属性home和业务,它们绑定到单选按钮。如果选择其中一个,底部的值将在主地址和业务地址之间切换(图4.8)。

    Figure 4.8. Method is updated from the radio button.

    我们的客户可以看到,他们有一个包裹被送到一个营业地址(埃里克汉切特在123街Ln,雷诺,内华达州),它不会作为礼物运送!将属性绑定到表单中的任何属性值都可以使事情变得更清晰和简单。我们现在需要在下一节中查看美国各州的选择框控件。

     
    4.2.3. 学习v-for指令
    我们的选择框控件列出了客户可以从中选择的状态。我们需要更新select下拉控件,以便刷新页面时状态显示在框中。让我们看看如何绑定状态值。替换索引.html在城市输入之后,使用以下列表中所示的标记。
    Listing 4.13. Binding values to our select box: chapter-04/bind-select.html

    1 将v­bind指令值属性赋给states.AL属性
    2 将v­bind指令值属性分配给states.AR属性。
    3 将v­bind指令值属性指定给states.CA属性。
    4 将v­bind指令值属性分配给states.NV属性。

    正如我们之前看到的,v­bind指令正在分配value属性。这次我们创建了一个名为states的新数据属性。在这个州的财产里,我列出了美国的州。states对象包含四个值。我们可以使用v­bind指令在选择框中访问它们。更新索引.html文件并将states对象添加到data对象。

    Listing 4.14. Adding the states property to the Vue instance data object:chapter-04/states.html

    更新完所有内容后,我们应该在页面底部模板的文本框中看到这些值(图4.9)。正如你所看到的,国家是明确的,清楚地表明发生了什么。

    Figure 4.9. State text property is displaying the correct state selected

    在本章的前面,我提到了下拉列表中的一个关键问题。在本例中,只列出了四个状态。随着状态列表的增长,我们需要为每个状态创建一个option>标记。这可能是乏味和重复的。幸运的是,Vue有一些东西可以帮助我们解决这个问题。它被称为v­-for指令。

    v-­for指令使得在列表或对象中循环值变得很容易,这非常适合我们的情况。为了实现这一点,我们将在state对象中定义所有状态。然后,我们将在使用v­bind指令时迭代每个状态,以便所有内容都匹配。我们来试试吧!

    这里发生了很多事情,所以我来细说一下。v­-for指令要求以state in states的形式使用特殊语法。states是源数据数组,而state是正在迭代的数组元素的别名。在这种情况下,州是阿拉巴马州,亚利桑那州,加利福尼亚州,等等。替换index.html在城市输入之后,使用如下所示的HTML。

    Listing 4.15. Updating the select drop down with v-­for: chapter-04/select-drop-down.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属性中的每个状态。

    Listing 4.16. HTML generated by the v­for directive: chapter-04/options.html

     这对我们的应用来说是个好消息。因为我们现在可以绑定这些值并用v­-for对它们进行迭代,所以我们不再需要硬编码每个美国州。我们的选择框可以根据创建states对象的方式动态增长。

    4.2.4. 没有可选的键值的v-for指令
    我提到键值是可选的,那么没有键值的v-­for指令会是什么样子呢?走一个快速的弯路,看看它是如何工作的,让我们从一个空的地方开始detour.html归档并创建一个全新的应用程序。创建一个Vue构造函数,并添加一个带有states数组的数据对象。
    Listing 4.17. Updating the states object in data: chapter 04-/detour.html

    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). 我们也可以通过一个接一个地添加链式修饰语(例如,v­model.trim.number). 让我们在应用程序的checkout页面中添加几个这样的修饰符。

    4.3.1. 使用.number修饰符

    .number修饰符用于自动将v­model指令中的值类型转换为数字。这在我们的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属性。

    Listing 4.19. Using the typeof operator on order.zip: chapter-04/type-of.html

     1 JavaScript typeof运算符返回未赋值操作数的类型。

    在我们添加.number修饰符之前,它会显示为一个字符串。现在它以数字的形式返回。在ZIP输入框中输入一个数字,然后重新呈现页面以查看新的输出,如图4.10所示。

    Figure 4.10. Type of value entered into the zip property.

    您可以在图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 v­model指令将.trim修饰符用于订单名财产。
    2 v­model指令将.trim修饰符用于订单.姓氏指令。

    要添加.trim修饰符,我们只需要在v­-model指令的末尾添加.trim。这将自动为我们修剪空白!现在我们可以将它添加到index.html.

    Listing 4.21. The .trim modifier on the address and city: chapter-04/trim-mod-add.html

    1 v­model指令将.trim修饰符用于order.address属性。
    2 v­model指令将.trim修饰符用于order.city指令。

    如果我们在浏览器刷新后查看页面底部的输出,我们会注意到空白被删除(图4.11)。

    Figure 4.11. An example of using the .trim modifier on the v­model directive.

    4.3.3. .lazy v-model修饰符
    最后一个修饰符是.lazy修饰符。正如我前面提到的,v­model指令在每个输入事件之后同步。实际上,这发生在每个字母键入后的文本框中。每次击键时都会同步该值。.lazy修饰符将改为在更改事件上同步。根据所使用的表单元素,更改事件在各种情况下发生。复选框或单选按钮在单击时将触发更改事件。输入文本框在失去焦点时将触发更改事件。不同的浏览器可能不会在相同的交互上触发更改事件,所以请记住这一点。
    通常,当添加到v­-model指令时,.lazy修饰符如下所示:

    练习

    使用本章学的知识回答以下问题:

    双向数据绑定怎么工作的?为什么你应该在你的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节中更详细地了解这一点。

    5.1. 显示可用库存消息
     
    每次向我们的购物车添加一个附加项目时,cartItemCount的computed属性都会更新。如果我们想让用户知道有多少是可用的呢?当可用库存即将用完时,让我们显示一些消息。我们将使用v-­if、v­-else-­if和v­-else指令来实现这一点。
     
    5.1.1. 使用v-if添加还有多少
    在我们开始之前,让我们添加更多的库存。这将使用户在购物车中放入更多物品时更容易向其显示消息。要添加库存,我们可以更新数据对象中的产品属性。在中编辑availableInventory产品属性index.html. 让我们将其从5改为10,如清单5.1所示。现在应该够了。
     
  • 相关阅读:
    hduoj 1865 1string 【大数】【菲波那切数列】
    poj 1664 放苹果【M的N划分】
    新年第一篇
    3、XCode: 如何添加自定义代码片段
    2、文件夹
    1、获取当前屏幕显示的页面
    运算符
    表单数据接收
    PHP进入MySQL数据库
    my SQL认识和进入
  • 原文地址:https://www.cnblogs.com/2008nmj/p/14620215.html
Copyright © 2011-2022 走看看