2.2 构建表单用户界面
本节要完成的构建用户界面的任务有:定义HTML文档结构,构建表单的各个部分,以及让用户来决定究竟是保存还是提交表单的细节信息。
本节主要学习内容
- 利用HTML5表单< input >元素类型及属性来提供小部件及数据验证。
- 利用data-*属性来保存每种产品的价格。
- 使用< output >元素来呈现单种产品金额小计与订单金额总计。
- 使用表单属性formnovalidate和formaction绕过验证,保存未完成的表单。
- 整个UI的构建工作按照以下7步进行。
- 第1步:创建index.html并加载外部文件。
- 第2步:创建联系方式明细部分。
- 第3步:创建表单的登录明细部分。
- 第4步:创建表单的订单明细部分。
- 第5步:创建表单的付款明细部分。
- 第6步:绕过数据验证,保存表单数据。
- 第7步:改变表单在旧浏览器中的行为。
接下来,让我们先从HTML文档开始。
2.2.1 定义表单的基本HTML文档结构
先在系统中创建一个新目录,最好能在Web服务器中创建,但对本章这个例子来说,倒不一定非得这么做。
第1步:创建index.html并加载外部文件
在新目录中创建一个index.html文件,然后把代码清单2-1中的代码粘贴进去,这些代码加载了外部依赖文件(CSS和JavaScript文件),定义了< form >元素、顶部的页眉以及底部的按钮。
订单分4个部分:本节介绍联系方式细节、登录细节与支付细节,下一节介绍订单细节。
2.2.2 使用表单输入类型email和tel,以及输入属性autofocus、required和placeholder
在构建订单之前,先来更详细地介绍一下新输入类型及属性,以及如何使用这些类型及属性尽量快速地构建表单。我们将利用email和tel输入类型以及autofocus、required和placeholder属性来逐步改善表单。
email和tel输入类型看上去和标准的文本输入元素相同,但如果用户在支持这两种输入类型的移动设备浏览器上浏览页面时,虚拟键盘布局就会根据用户所键入的数据类型而发生改变,如图2-2所示。
对于email输入类型,浏览器还要检查用户输入的内容是否为有效的电子邮件地址。如果是无效数据,当用户提交表单时,就会引发错误。错误类型随不同的浏览器而定,具体呈现方式会有所不同,如图2-3所示。
接下来介绍一下3个属性:autofocus、required和placeholder。
autofocus属性的用处很明显:用于定义在页面加载时应该获取焦点的输入元素。对于required属性也不难理解,当某个字段必须包含用户输入才能有效时,将用到这个属性。本章稍后将介绍更多的HTML5表单验证方面的知识。placeholder属性则用于定义在某个为空的或者非活跃字段内出现的一小段文本。用户一旦在该字段内输入内容,占位符(placeholder)文本就被清除,代之以用户输入内容,如图2-4所示。
第2步:创建联系方式明细部分
让我们将上述新特性都应用到联系方式明细部分中,具体代码如下面的代码清单2-2所示,照例应将其添加到index.html中。这些代码应紧跟着代码清单2-1中的< h1 >Order Form</ h1 >.
**
2.2.3 使用表单输入属性required**
登录明细部分是该订单最普通的部分,它要求用户输入两次账户密码以确认输入无误。这里的代码没有用到任何HTML5的新特性,本章稍后将介绍如何使用约束验证API来实现密码确认功能。
第3步:创建表单的登录明细部分
此处,只需将代码清单2-3所示的代码粘贴到上一节完成的index.html代码末尾即可,然后我们会继续介绍一个更有趣的部分。
2.2.4 使用number输入类型与min、max、data-*输入属性,以及< output >元素来构建具备计算功能的表单
如图2-5中的表单,你可能觉得在订单明细部分中没有用到太多HTML5表单功能吧?未必如此。
订单明细部分中用到了如下几个HTML5特性。
- 用于实现数量输入字段的number输入类型;
- 用于验证quantity输入的min和max属性;
- 存储价格数据的data-*属性;
- 显示总金额的output元素。
number输入类型
在支持number输入类型的浏览器中,该输入类型会显示为一个新的UI小部件:一种数值微调框控件,用户可以通过按动控件旁边的向上箭头按钮来增加数值,按动向下箭头按钮来减少数值,如图2-6所示。
number输入类型还有两个密切相关的新属性:max和min属性。
这两个属性定义了用户在number输入字段中所能输入的最大值与最小值,另外,它们还可以定义用于滑块选择器(由range输入类型实现)的最大值与最小值。data-*则是另外一个新的属性,它能自动随着用户输入,轻松地计算出相应的总值。
data-*属性
在本例所要创建的订单中,用户应该能输入每种产品的购买数值,订单应能自动计算出单种产品的总金额以及整个订单的总金额。为了实现这两项功能,首先需要知道每个产品的单价。过去,你可能会在每行中插入一个隐藏字段来保存每种产品的单价,或者通过JavaScript数组来保存单价数据,然后再通过查找,获取相应产品的单价。这两种解决方法都不是很简洁。来看看HTML5的data-*属性是怎样解决这个问题的吧!
通过HTML5的data-*属性,任意的键/值对数据都能绑定到某一元素上。JavaScript随后会读取这一数据,继而进行计算并执行客户端操作。
data-*属性的用法很简单:在键前加上data-前缀构成属性名,然后再给它赋值。比如,可以将一个单价数值绑定到数值输入字段上,代码如下所示:
然后,通过侦听字段的改变,将data-price属性值乘以用户的输入值,就得到了单种产品的总金额。稍后再学习如何取回data-price属性值,现在先了解一下本节要介绍的最后一个HTML5新特性:output元素。
它的作用正如其名:将输出结果显示给用户。根据某些数据(如用户在input元素中所输入的数值)来显示计算结果就是它的一个典型用例。随着我们这个订单项目的不断完善,稍后就会向你介绍如何更新output元素中的数值,接下来,先将这些新特性应用到代码上。
第4步:创建表单的订单明细部分
紧接着的代码清单包含了订单明细部分的实现代码。让我们实际应用一下以上介绍的新特性吧。特别要注意的是,对于兼容HTML5的浏览器而言,这些新特性是如何简化编码任务的。只需将代码清单2-4所示的代码直接粘贴在上一步完成的index.html源代码的下面即可。
2.2.5 使用表单输入类型month和pattern输入属性
表单的付款明细部分要求用户输入信用卡详细信息:持卡人姓名、信用卡号、有效期、CVV2安全码(大多数信用卡的背后都有这个号码)。这些字段将要用到在联系方式明细部分介绍过的HTML5表单特性:required和placeholder输入属性。付款明细部分还要另外使用两个新特性:month输入类型与pattern输入属性。
month类型能让用户从日期选择器部件中选择年月。HTML5定义了一些日期相关的类型:date、datetime、datetime-local、month、week以及time。目前,在对于这些部件和验证的支持上,大多数浏览器发展得都很缓慢,然而Opera却是个例外,它很早就能非常好地支持这些类型了——当然,它的日期选择器小部件实在是很丑,如图2-7所示。
本章稍后将介绍针对不兼容month类型的浏览器的回退方法,让用户更直观地输入月份,而不是通过一个简单的文本框来输入。
pattern输入属性
pattern属性能指定一个正则表达式模式来测试字段内输入的数据。在订单中的card_number及card_cvv2字段中,将用这个属性来确保输入的数据是数值类型,并且数值长度符合要求。
使用pattern属性时,可以用title属性来提示用户,让他们了解到该字段所需输入数据的格式。当鼠标指针移动到该字段的上方时,就会显示出一个提示框。如果用户输入了无效值,还需要加上错误信息,如图2-8所示。
第5步:表单的付款明细部分
下面就让我们来添加上述介绍的新特性:利用月份选择器部件来轻松地输入日期,并用pattern属性来定义有效数据模式。将代码清单2-5所示的代码直接添加到上一步完成的index.html的源码中,要紧跟着上一步添加的代码。
试试看
现在,这个表单应该可以用了。在那些对HTML5新特性支持较好的浏览器中,你能看到这些新的输入类型、属性以及验证功能都生效了。在下一节中,我们将实现暂时保存表单数据(以备后续完善)与立刻提交表单这两种功能,以供用户选择使用。
2.2.6 提交还是保存?由用户来选择——formnovalidate和formaction输入类型
用户有时不可能用一次会话就填完表单,所以需要提供保存当前进程的方法,以便他们后续进行修改。由于用户可能会需要快速跳离表单页面,所以在保存表单时,我们不能强制用户去纠正那些验证提示出错的项目,那样做是不利于用户体验的。只有当表单最终完成并提交时,才应该要求用户去修改验证出错的项目。因此,还需要让用户绕开验证操作。
对表单使用新的novalidate属性,我们可以强制整个表单绕开验证操作。只有当我们想使用新的HTML5表单部件,而又不想使用任何新的验证特性的时候,这才是一个不错的方法。绕开验证还有另外一个方法,那就是利用一个单独的按钮来保存当前进程,这就用到了formnovalidate属性,也只有在用到这一属性的时候,才能绕开验证操作。另外,因为要保存而非提交数据,所以还需要改变表单的formaction属性,调用一个不同的URL。在HTML5中,利用formaction属性即可。
第6步:绕过表单验证,保存表单数据
下面就用上述这些新特性来改动一下订单的Save Order(保存订单)按钮。
- 在index.html中找到下面这行代码:
- 将它替换成:
- 在IE10(或更高版本的IE)中打开订单页面,不填写任何字段。
- 单击Submit Order(提交订单)按钮,这时Name(名称)字段就会弹出一个错误消息提示,提示该字段必须填写。
- 单击Save Order按钮,会发现没有进行验证,表单所提交到的URL是/save,而不是/submit。
很简单,对吧?遗憾的是,不可能这么简单,在不支持这些新特性的浏览器中,这种功能根本无法实现。不过,我们可以用一些JavaScript代码来修复这个问题。
第7步:针对旧浏览器,修改表单行为
在旧浏览器中,这个应用应该也能变换表单行为,当用户提交表单时,应能调用不同于保存数据时的URL。
在index.html所在目录中创建一个叫做app.js的新文件,将代码清单2-6所示的代码添加到这个新文件中。
如果在不支持formaction属性的浏览器(如IE9)中打开页面,单击Submit Order按钮,表单会被提交到/submit这个URL上;单击Save Order按钮,表单将被提交到/save。你可能会注意到,这中间并没有什么验证,不要着急,稍后将介绍一种回退方案。
进度查看
到目前为止,我们已经创建了表单的几个主要部分:联系方式明细、登录明细、订单明细以及付款明细。对于有些浏览器而言,使用HTML5新引入的输入类型email或tel、required输入属性,以及通用的data-*属性和output元素,可以减少应用所需的代码。另外,对于另外一项任务,即如何在保存未完成表单时绕过数据验证,利用formnovalidate和formaction这两个新的输入属性,也能在支持它们的浏览器上取得代码简化的效果。
下一节将实现订单明细部分内部所用的计算逻辑,获取用户所输入的数值,计算并显示单件物品以及整个订单的总金额。