HTML5 和 VS2015 高级教程(一)

原文:Pro HTML5 with Visual Studio 2015

协议:CC BY-NC-SA 4.0

一、开始之前

在本书中,我将展示如何利用超文本标记语言(HTML5)中包含的非常酷的新特性。这将是非常实际的大量代码样本和工作网页。然而,在我们开始之前,我将搭建舞台,并为我们将要去的地方提供一些背景。一般所说的 HTML5 包含了很多技术,HTML 只是冰山一角。

在这一章中,我将简要回顾当前和历史上托管网站的操作环境。我还将描述可用的开发工具。虽然这本书特别关注 Visual Studio 2015,但也有一些免费的替代方法可以帮助您完成大多数练习。最后,我将快速盘点一下当前和未来浏览器对 HTML5 的支持。

审查网络环境

为了从 web 开发人员的角度更好地理解 HTML5,我将首先回顾一下我们所处的 web 环境。这将是一个基本的概述,对大多数读者来说相当熟悉。然而,我经常发现偶尔后退一步是有用的,可以获得更好的视角。

基本的 HTTP 页面

在网络的早期,这个模型非常简单。它包括一个负责提供网页的网络服务器和一个在客户端呈现网页的浏览器。在微软的堆栈中,Internet 信息服务(IIS)提供了服务器组件,而 Internet Explorer 是事实上的浏览器。当然,还有其他浏览器,比如网景。浏览器将通过传递超文本传输协议(HTTP) GET 请求中的地址(URL)向 web 服务器请求页面。服务器将通过提供一个 HTML 文档来响应,然后由浏览器呈现,如图 1-1 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-1。

A simple page-centric web model

如果网页包含一个带有输入字段的表单,浏览器将提供这些数据的输入。当提交页面时,这些数据通过 HTTP POST 请求发送到 web 服务器。web 应用将对这些数据做一些事情,然后返回一个更新的网页。然后,浏览器会在客户机上呈现整个页面。

在这里,我想重点介绍两个即使在当今的网络环境下仍然具有重大影响的关键方面:

  • 该模型非常以页面为中心。
  • web 开发包括服务器和客户端两个方面。
以页面为中心的网站

正如我提到的,网站主要集中在网页上。请求、返回并呈现页面。页面上的数据被发送到服务器并进行处理,然后返回并呈现更新后的页面。因为 web 服务器是无状态的,所以它不知道先前返回的页面。这就是为什么整个页面必须提交和返回。当前和未来的技术正在帮助摆脱这种范式,我将在本书中演示其中的许多技术。然而,以页面为中心的设计仍然很流行,而且可能会持续一段时间。

客户机-服务器模型

构建 web 应用时,需要考虑服务器和客户端组件。在服务器上,IIS 响应我提到的 HTTP 请求。对于静态内容,HTML 文件可以简单地存储在 IIS 中的一个虚拟文件夹中,不需要编程。对于动态内容,需要一个 web 应用来生成 HTML。进入 ASP.NET。

ASP.NET 允许你编写代码来动态创建 HTML。例如,页面可以查询数据库,并使用从数据库返回的数据填充网格。同样,HTTP POST 请求中呈现的数据可以写入数据库。此外,虽然 web 应用通常被认为是无状态的,但 ASP.NET 提供了几种在请求之间保存信息的技术。

在客户端,浏览器负责呈现内容。这些内容以 HTML 的形式提供,实质上是嵌入了格式化标签的文本。此外,级联样式表(CSS)可用于指示浏览器如何格式化内容。然而,对这些 HTML 标签和 CSS 结构的支持会因浏览器的不同而不同,这也是 web 开发的一些最大挑战。

改善网络体验

以页面为中心的方法是提高整体用户体验的主要障碍。刷新整个页面效率不是很高。为了解决这一问题,引入了两项关键改进:

  • 客户端脚本
  • 异步 JavaScript 和 XML (AJAX)
使用客户端脚本

现在所有的浏览器都提供了运行客户端脚本的能力,这些脚本主要是用 JavaScript 编写的,尽管其他的如 VBScript 也可以在一些浏览器中运行。在浏览器中运行脚本的能力是一个巨大的改进。例如,脚本可以根据用户输入隐藏或显示某个部分,或者修改内容的格式。因为这发生在客户端,所以没有必要往返服务器。这使得网站看起来响应速度更快。

Caution

JavaScript 可以在客户端禁用,您应该考虑并测试禁用脚本后您的页面将如何运行。

使用 AJAX

AJAX 是异步 JavaScript 和 XML 的缩写。虽然有点用词不当,因为它不一定是异步的、使用 JavaScript 或使用 XML,但该术语指的是支持客户端脚本在典型的页面刷新场景之外与 web 服务器通信的技术集合。简而言之,AJAX 使用 JavaScript 从 web 服务器请求数据。然后,它使用文档对象模型(DOM)更新页面内容。这允许根据需要更新网页的一部分,而不需要完全刷新。

AJAX 还可以用来独立于托管网页的 web 服务器调用 web 服务。您可以使用 AJAX 访问第三方提供的数据,比如股票报价或货币兑换。您还可以调用自己的 web 服务来执行实时更新或根据用户输入加载数据。例如,您可以提供产品搜索功能,并使用 AJAX 调用返回匹配产品的 web 服务。同样,这完全独立于标准的页面刷新范例。

图 1-2 展示了当今大多数网站使用的更健壮的模型。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-2。

A more robust web environment

由于包含了客户端脚本和 AJAX 请求,您现在可以创建更具交互性和响应性的基于 web 的解决方案。当然,这需要更复杂的 web 应用和广泛的技术在服务器和客户机上使用。

回顾网络技术

让我们快速回顾一下在构建漂亮的交互式 web 应用时可能需要使用的各种技术。

  • HTML:超文本标记语言是向浏览器传递内容的主要方式。除了显示的实际文本之外,HTML 还包含控制内容格式的嵌入标记。标签用于对齐节和表中的内容,修改文本属性,以及包含非文本内容,包括链接和图形。
  • CSS:级联样式表被用作控制网页视觉方面的中心位置,比如字体、颜色、背景图像和边距。它们被称为级联,因为样式选项是在 DOM 的不同层次上定义的。您可以在一个样式表中定义站点级样式,然后根据需要提供其他样式表,以便为特定页面、部分或类进一步定义或覆盖这些样式。
  • DOM:浏览器呈现的 HTML 类似于 XML 文档,文档对象模型定义了这个文档的结构。这用于以编程方式访问和修改文档内容。
  • ECMAScript:客户端脚本由浏览器解释和执行。为了提高跨浏览器兼容性,ECMAScript 标准定义了脚本语言的语法和功能。JavaScript 是 ECMAScript 标准的一种方言。

Note

从历史上看,JavaScript 和 JScript 是同一种脚本语言的两种实现。微软将其实现命名为 JScript,以避免与 Sun 的商标问题,但它们本质上是相同的,并遵循不断发展的 ECMAScript 标准。随着 Internet Explorer 10 的推出,微软正在摆脱这种区分,将其脚本语言称为 JavaScript。为了保持趣味性,微软仍然提供了一种 JScript 语言,它提供了对。NET,与 JavaScript 有很大不同。在本书中,我将 JavaScript 称为符合 ECMAScript 的标准脚本语言。

探索 HTML5

那么,HTML5 在这个等式中处于什么位置呢?几乎无处不在!通常被归类为 HTML5 的实际上是一组与 web 浏览器标准化相关的广泛规范,其中许多与 HTML 无关。我将在这里简要总结一下,然后在本书的其余部分详细演示这些特性。以下是一些你应该记住的事情:

  • 许多规范尚未最终确定。大部分核心规范已经完成,但一些高级功能仍有待更改。
  • 浏览器对这些功能的支持会有所不同。浏览器厂商正在积极地在每个后续版本中加入新功能。
  • 这些规范为每个浏览器供应商留下了决定如何实现每个特性的空间。例如,所有兼容的浏览器都将提供日期选择器控件来输入日期,但每个浏览器可能以不同的方式实现这一点。

HTML5 的总体趋势是在浏览器中提供更多的原生支持。正如你将在本书中看到的,浏览器提供了越来越多令人印象深刻的功能。这将使您能够用更少的工作构建更好的 web 应用。

审阅标记更改

正如您所料,HTML5 在标记元素中包含了一些重要的改进。有一个相当大的新标记元素列表,我将在第二章、 3 和 4 中演示其中的许多。

通用的<div>元素仍然受支持,但是也提供了新的、更加特定于上下文的元素。我将在第四章中解释和演示这一点。新的内容标签如下:

  • <article>
  • <aside>
  • <footer>
  • <header>
  • <hgroup>
  • <nav>
  • <section>

提供了几个新的输入类型元素,允许本地格式化和验证功能。这些将在第二章和第三章中描述。新类型如下:

  • color
  • datetime(以及datetime-localdatetimemonthweek)
  • email
  • number
  • range
  • search
  • tel
  • url

还有一些新元素使您能够使用浏览器实现的控件,如下所示:

  • <audio>
  • <figcaption>
  • <figure>
  • <meter>
  • <output>
  • <progress>
  • <video>

HTML5 还引入了一些其他元素,我将在后面详细描述。我将在第八章的中演示<audio><video>标签。新的<canvas>元素提供了一些重要的图形功能,我将在第十章中演示这一点。

理解级联样式表

像 HTML 一样,CSS 功能是由一组不断发展的规范定义的。当前发布的推荐标准是 CSS 2.1,下一个正在起草的版本称为 CSS3。然而,它被分解成 50 多个“模块”,每个模块都有单独的规范。在撰写本文时,这些模块中只有几个已经成为官方的 W3C 推荐标准(REC ),还有几个处于 W3C 候选推荐标准(CR)状态。

Tip

由于每个 CSS 模块的状态都在不断变化,有关每个模块当前状态的完整信息,请参见 www.w3.org/Style/CSS/current-work 中的文章。

因此,目前实际的 CSS3“规范”是一个移动的目标,浏览器对这些规范的支持也将有所不同。然而,已经有许多很酷的功能普遍可用,我将在第四章中演示其中的一些。

查看其他 HTML 功能

实际的脚本语法由我前面提到的 ECMAScript 规范定义。目前的版本是 5.1,发布于 2011 年 6 月。虽然它实际上不是 HTML5 规范的一部分,但符合 HTML5 的浏览器应该支持 ECMAScript 5.1 标准。然而,正如我所说的,这个规范描述了语言语法和一些内置函数,比如元素选择器。

除了语言规范之外,还有相当多的其他规范松散地包含在 HTML5 的保护伞下,它们定义了特定的客户端功能。我将在第五章中演示其中的许多,其余的将在后面的章节中介绍。新功能包括以下内容:

  • 拖放:这提供了选择一个项目并将其放到网页上的另一个项目上的能力。我将在第十四章中演示这一点。
  • Web 工作器:这允许您在单独的线程上执行脚本。这包括与工作人员通信的机制和在多个网页之间共享工作人员的能力。我会在第五章中解释这一点。
  • Web 存储:这包括用于隔离连接到同一个站点的多个选项卡之间的会话数据的sessionStorage,以及用于在会话关闭后在客户端上存储数据的localStorage。IndexedDB 是另一种客户端数据存储技术,我将在第十一章中演示。
  • 地理定位:这不是官方规范的一部分,但在讨论 HTML5 特性时通常会包括在内。地理定位定义了一个 API,可以从 JavaScript 调用该 API 来确定当前的地理位置。浏览器如何实现这一点取决于可用的硬件。在支持 GPS 的设备上,它将使用 GPS 卫星。如果 GPS 支持不可用,它将在可能的情况下使用 Wi-Fi 来确定位置。移动设备可以使用蜂窝塔三角测量。如果所有这些都失败了,IP 地址至少可以提供一些位置的估计。显然,准确性会有很大的差异,API 会处理这一点。我将在第十二章中演示地理定位。
  • Web sockets:这提供了网页(浏览器)和服务器之间的异步通信。一旦建立了连接,服务器就可以向客户端发送实时更新。这将在第十三章中演示。

选择开发工具

有几种开发环境可以用来创建利用 HTML5 特性的 ASP.NET 应用。我将在这里简要介绍它们,并在后续章节中更详细地介绍它们。需要知道的关键一点是,Visual Studio 有一些免费的替代品。

使用 Visual Studio 2015

Visual Studio 2015 是构建 ASP.NET 应用的首要开发环境。我不会在这里说太多,因为我将在本书中主要使用它来演示 HTML5 的实现。但是,如果购买 Visual Studio 的成本过高,有一些免费的替代方案仍然可以让您完成本书中的大部分练习。

Tip

对于大多数练习,您可以使用 Visual Studio 的早期版本。配置项目的一些细节会因旧版本而异,尤其是在第二章和第三章中。然而,本书中的大多数 HTML、CSS 和 JavaScript 示例也适用于任何版本的 Visual Studio。

使用微软的网络矩阵

微软的 WebMatrix 是一个轻量级集成开发环境(IDE ),专门用于构建网站。虽然不仅限于 ASP.NET 页面,但您可以构建成熟的 ASP.NET 应用。它包括 SQL Server Compact,这是基于文件的 SQL Server 版本。它还使用 IIS Express 来承载用于调试的本地网站。这与 Visual Studio 2012 中提供的托管环境相同,它取代了以前版本的 Visual Studio 中使用的 ASP.NET 开发服务器。

ASP 页面基于 ASP.NET MVC 并使用 Razor 视图引擎。因此,文件扩展名是.cshtml(如果使用 Visual Basic,则是.vbhtml)。然而,不支持带有.aspx标记文件和单独的.cs代码隐藏文件的经典 ASP 模型。您可以创建.aspx文件,但是添加代码隐藏文件并不实用。

您可以从以下网址下载并安装 WebMatrix 第 3 版: www.microsoft.com/web/webmatrix 。创建新站点时,如果使用 Starter Site 模板,它将创建一个熟悉的默认 ASP web 应用,如图 1-3 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-3。

The default ASP application Note

当选择 Starter 站点模板时,我在尝试下载模板时收到了一个 404 错误。我发现其他人也经历了这个错误。然而,它似乎是间歇性的,因为当我稍后再次尝试时,它工作得很好。

图 1-4 显示了 IDE。请注意。用于页面实现的扩展和 Razor 语法。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-4。

The WebMatrix IDE

WebMatrix IDE 包括管理 SQL Server 数据库的能力。您可以创建新的数据库或连接到现有的 SQL Server 数据库。您可以创建和修改表格,以及查看和编辑数据。也可以运行 SQL 查询,如图 1-5 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-5。

WebMatrix database IDE

关于使用 WebMatrix 的更多信息,我建议从 www.microsoft.com/web/post/how-to-use-the-starter-site-template-for-aspnet-web-pages 的教程开始。

使用 Visual Studio 社区版

微软在 2014 年 11 月公布了 Visual Studio 的免费版本,名为 Community Edition。已经有了其他的免费版本,比如 Visual Studio Express for Web 但是,Community Edition 的重要之处在于它的外观和功能就像 Visual Studio Professional 的完整零售版一样。Visual Studio 速成版面向特定的技术(例如,用于 Web 或桌面)。此外,速成版没有与 Team Foundation Server 集成,并且不支持 Visual Studio 扩展。

社区版在功能上等同于专业版。它的限制主要基于谁可以使用它。一般来说,任何学术或非盈利的使用都是允许的。企业组织也可以使用它,但有一些限制。更多详情,请参见 www.visualstudio.com/en-us/products/visual-studio-community-vs 的文章。如果这些限制是一个问题,您应该考虑 Visual Studio 的一个 Express 版本,它也是免费的,但是功能有限。

可以在 https://www.visualstudio.com/en-us/downloads/visual-studio-2015-downloads-vs 下载 Visual Studio 社区版。

ASP.NET 5

ASP.NET 5 的最新版本与以前的版本有很大的不同。这篇文章, http://docs.asp.net/en/latest/conceptual-overview/aspnet.html ,很好的概述了 ASP.NET 5 中引入的变化。创建新项目时,Visual Studio 2015 为版本 5 和 4.6 提供了单独的模板,因为结构非常不同。图 1-6 显示了可用的模板。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-6。

The ASP.NET project templates

本书中的大多数主题在两个版本中都同样适用。对于您将要构建的示例项目,区别仅在于项目是如何创建的,以及您需要添加和编辑哪些文件。

章节练习

本书中的练习将使用 4.6 和 5 以及 WebMatrix 应用。第二章和第三章将使用 ASP.NET 4.6,你将修改标准的 Web 表单和 MVC 应用。第四章将像第六章一样使用 WebMatrix,因为它使用已完成的第四章项目作为其起点。剩下的章节练习使用新的 ASP.NET 5 结构。第九章使用 SQL Server 和实体框架,但大部分章节只是基本的 HTML、CSS、JavaScript。如果您喜欢使用单一的项目类型,您可以调整初始步骤以满足您的需要。

项目结构

当你第一次创建一个 ASP.NET 5 项目时,你会发现文件夹结构发生了显著的变化。典型结构如图 1-7 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-7。

A sample project structure

wwwroot文件夹是放置静态网页文件的地方,比如 HTML、CSS、JavaScript 文件以及其他内容,包括图像、音频和视频文件。编译后的文件(如控制器、视图和 web 表单)放在其他文件夹中。您将主要处理wwwroot文件夹中的文件。

请注意,这里没有web.config文件。使用 ASP.NET 5,配置信息可以放在多个文件中,并且可以是各种格式,包括 JSON。ini 文件和环境变量。项目模板生成如图 1-7 所示的global.jsonproject.json等 JSON 文件。我将在第五章中进一步解释这一点。

解密浏览器对 HTML5 的支持

将应用迁移到 HTML5 的所有工作都是基于这样一个假设,即大多数浏览器都兼容 HTML5。这就要求浏览器供应商挺身而出,提供兼容 HTML5 的浏览器,并让公众普遍接受它们。这也包括移动设备,这是推动 HTML5 合规性的关键部分。普遍的共识是,每个人都在朝着这个方向快速前进。

正如我前面提到的,实际的 HTML5 规范仍在定义中。根据 HTML5 编辑伊恩·希克森的说法,在最终建议完成之前,最初的估计是 2022 年。然而,随着规范的大部分被最终确定,供应商们正在实现它们,所以在当前使用的浏览器中已经有了很多。作为 web 开发人员,我们应该把重点放在现在普遍可用的或预计很快可用的功能上,这些就是我将在本书中涉及的功能。

http://html5test.com 有一个非常好的网站,它提供了当前可用的和仍在开发中的浏览器的概要。每个浏览器都根据其支持的 HTML5 特性获得积分。除了允许您比较浏览器的总体分数之外,分数还按功能区域细分,因此您可以看到大多数浏览器对哪些区域的支持较好。

摘要

HTML5 涵盖了一系列广泛的技术,包括对 HTML 标记、级联样式表和客户端脚本的改进。此外,浏览器有一些重要的增强,使得提供一些优秀的 web 应用变得更加容易。虽然官方规范仍在发展中,浏览器供应商也在追赶,但已经有相当多的功能可用。此外,正如您将在接下来的几章中看到的,Visual Studio 和 ASP.NET 平台已经扩展到利用 HTML 特性集。

二、ASP.NET Web 窗体

在这一章中,我将演示 HTML5 定义的一些新的输入类型,并向你展示如何在 ASP.NET web 表单中使用它们。通常,当需要在表单上输入数据时,会使用TextBox控件。用户可以在TextBox中输入各种数据,包括字符串、数字、日期等等。为了确保数据有效,表单需要提供服务器端或客户端验证逻辑。HTML5 规范提供了几个新的输入类型,可以为您完成大部分工作,并实现更好的客户体验。

定义了以下输入类型(然而,并非所有的浏览器都支持它们):

  • select
  • color
  • datetime(包括datetime-localdatetimemonthweek)
  • email
  • number
  • range
  • tel
  • url

当您使用 ASP.NET 构建 web 表单时,发送到浏览器的实际 HTML 是由. NET 生成的。我将向您展示 ASP.NET 插入新输入类型的方式。此外,使用一些新的 HTML 元素需要一些额外的操作,所以我也将演示如何处理。

引入新的输入类型

我将从一个相当简单的例子开始,演示如何使用新的电子邮件控件结合占位符属性来快速提供客户端指令和验证。首先,您将使用 Visual Studio 模板创建一个标准的 ASP 项目,然后修改注册页面。然后,您将检查正在呈现的 HTML。

创建 ASP.NET 项目

在本章中,您将使用 Visual Studio 2015 中的标准 Web 窗体模板创建一个 ASP.NET 项目。启动 Visual Studio 2015。从起始页中,单击新建项目链接。在新建项目对话框中,选择 Web 类别,选择 ASP.NET Web 应用模板,输入章节 2 作为项目名称,选择合适的位置,如图 2-1 所示。如果选择了应用洞察,请将其关闭。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-1。

Creating an ASP.NET Web Application project

Visual Studio 的早期版本提供了三种不同的创建 web 应用的方法。

  • Web 表单最适合相当轻量级的网页。
  • MVC 为构建更复杂的 web 应用提供了一个框架。
  • Web API 主要用于创建 Web 服务。

虽然这三种技术中的一些概念是相似的,但是它们是在完全不同的堆栈上实现的。从开发人员的角度来看,一旦选择了一种方法,就不容易转换到另一种方法。此外,技能组合不容易转移到其他技术。在 MVC 6 中,微软将这三者合并成一个单一的实现。

如果您使用过 Visual Studio 的早期版本,您会注意到由此产生的一个细微差别。当选择项目类型时,您只需选择 ASP.NET 网络应用。选择使用哪种风格的应用被推迟到下一步,在那里选择模板。模板定义了在您构建新项目时为您创建的文件。与 Web 窗体应用相比,MVC 应用需要不同的文件和文件夹。

在下一个对话框中,如图 2-2 所示,选择 Web Forms 模板。请注意,其中一个可用的样式(Web Forms、MVC 或 Web API)会根据所选的模板自动选中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-2。

Choosing the Web Forms template

使用电子邮件控件

在第一个练习中,您将使用placeholder属性让用户知道该字段需要一个电子邮件地址。

EXERCISE 2-1. MODIFYING THE REGISTRATION PAGEIn the Chapter2 project, open the Register.aspx page, which you’ll find in the Account folder.   There are several div elements in the fieldset node that include the input fields. The first one is for the Email field. Change this as follows by entering the attributes shown in bold:

<asp:TextBox runat="server" ID="Email" CssClass="form-control" TextMode="Email"

placeholder="use your email address" Width="200" />

<asp:RequiredFieldValidator runat="server" ControlToValidate="Email"

CssClass="text-danger" ErrorMessage="The email field is required." />

Try viewing this page with several different browsers. Notice that the email validation message looks different in each. In Firefox this will look like Figure 2-6, and in Opera it looks like Figure 2-7.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-7。

The invalid e-mail message in Opera

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-6。

The invalid e-mail message in Firefox   Close the browser and stop debugging.   For this example, we used Google Chrome as the browser. If you want to use a different browser, you can select it from the drop-down list in the menu, as shown in Figure 2-5.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-5。

Selecting the browser to use for debugging   If you enter an invalid email address, you should see the error message shown in Figure 2-4 when you attempt to submit the page.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-4。

The invalid email error message   Start the application by pressing F5. Using the Chrome browser, the Register page will look like Figure 2-3. Notice the text in the Email field.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-3。

The initial Register page   Tip

该下拉列表自动包括当前安装的所有浏览器。您不必做任何事情来添加它们。如果安装新的浏览器,您需要重新启动 Visual Studio,它才会被包括在列表中。如果使用 Internet Explorer,浏览器将与调试器集成得更好。例如,当您关闭浏览器时,Visual Studio 将自动停止调试。然而,当测试 HTML5 支持时,除了 Internet Explorer 之外,您还需要使用其他浏览器。

使用页面检查器

使用 Internet Explorer 显示注册页面。选择工具下拉菜单,然后单击 F12 开发人员工具链接。这将允许您查看实际生成的 HTML。按 Ctrl+B 启用元素选择,然后单击电子邮件字段。这将高亮显示相关标记,如图 2-8 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-8。

The HTML generated for the email control Tip

大多数其他浏览器都有类似的特性,允许您检查表单内容,这通常通过它们的工具菜单来访问。

除了相当神秘的控件nameid,这是标准的 HTML5 语法。特别是,请注意以下属性;email type值和placeholder属性是 HTML5 中的新特性:

type="email"

placeholder="use your email address"

您在Register.aspx页面中输入的placeholder属性不是 ASP.NET 属性。它不是由处理的。NET,而是直接传递给生成的 HTML。

还要注意右边的窗格,它提供了几个用于查看 CSS 样式的选项卡。我们选择了 Attributes 选项卡,它显示了元素的所有属性值。其他选项卡显示应用的样式。停止调试器以关闭页面检查器。

探索其他输入类型

HTML5 引入了其他几种输入类型。为了看到他们的实际行动,您将添加一个反馈表单,其中包含一些相当做作的问题。这些将实现您可以使用的其他类型。

Tip

要获得每个输入元素的详细解释,请查看实际的 HTML5 规范。这个地址将把你带到输入元素部分: www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#the-input-element

实现反馈表

在下一个练习中,您将创建一个新表单并添加几个输入控件,每种类型一个。创建完表单后,我将讨论每个控件。

EXERCISE 2-2. ADDING A FEEDBACK FORMOpen the Chapter2 project in Visual Studio if not already open.   In the Solution Explorer, right-click the Chapter2 project and click the Add and Webform links. Enter Feedback when prompted for the form name.   This will create a new form with a single div, as shown in Listing 2-1.

清单 2-1。空白表单实现

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Feedback.aspx.cs"

Inherits="Chapter2.Feedback" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml

<head runat="server">

<title></title>

</head>

<body>

<form id="form1" runat="server">

<div>

</div>

</form>

</body>

</html>

Within the empty div, enter the code shown in Listing 2-2. This will add several fields that each demonstrate one of the new input types.

清单 2-2。添加反馈字段

<fieldset>

<legend>Feedback Form</legend>

<ol>

<li>

<asp:Label ID="lblURL" runat="server"

AssociatedControlID="URL">Default home page</asp:Label>

<asp:textbox runat="server" ID="URL" TextMode="Url"></asp:textbox>

</li>

<li>

<asp:Label ID="lblOptions" runat="server"

AssociatedControlID="Options">Default browser</asp:Label>

<asp:DropDownList ID="Options" runat="server">

<asp:ListItem Text="Internet Explorer" Value="1"></asp:ListItem>

<asp:ListItem Text="Google Chrome" Value="2" Selected></asp:ListItem>

<asp:ListItem Text="Firefox" Value="3"></asp:ListItem>

<asp:ListItem Text="Opera" Value="4"></asp:ListItem>

</asp:DropDownList>

</li>

<li>

<asp:Label ID="lblBirthday" runat="server"

AssociatedControlID="Birthday">Birthday</asp:Label>

<asp:TextBox runat="server" ID="Birthday" TextMode="Date"></asp:TextBox>

</li>

<li>

<asp:Label ID="lblMonth" runat="server"

AssociatedControlID="Month">Favorite Month</asp:Label>

<asp:TextBox runat="server" ID="Month" TextMode="Month"></asp:TextBox>

</li>

<li>

<asp:Label ID="lblWeek" runat="server"

AssociatedControlID="Week">Busiest Week</asp:Label>

<asp:TextBox runat="server" ID="Week" TextMode="Week"></asp:TextBox>

</li>

<li>

<asp:Label ID="lblStart" runat="server"

AssociatedControlID="DateTime">Start Date/Time</asp:Label>

<asp:TextBox runat="server" ID="DateTime"

TextMode="DateTimeLocal"></asp:TextBox>

</li>

<li>

<asp:Label ID="lblTime" runat="server"

AssociatedControlID="Time">Current Time</asp:Label>

<asp:TextBox runat="server" ID="Time" TextMode="Time" ></asp:TextBox>

</li>

<li>

<asp:Label ID="lblPhone" runat="server"

AssociatedControlID="Phone">Phone</asp:Label>

<asp:TextBox runat="server" ID="Phone" TextMode="Phone"></asp:TextBox>

</li>

<li>

<asp:Label ID="lblRange" runat="server"

AssociatedControlID="Range">Overall satisfaction</asp:Label>

<asp:TextBox runat="server" ID="Range" TextMode="Range"

Width="200" Height="30"></asp:TextBox>

</li>

<li>

<asp:Label ID="lblColor" runat="server"

AssociatedControlID="Color">Preferred color</asp:Label>

<asp:TextBox runat="server" ID="Color" TextMode="Color"></asp:TextBox>

</li>

<li>

<asp:Label ID="lblScore" runat="server"

AssociatedControlID="Score">Overall Rating</asp:Label>

<asp:TextBox ID="Score" runat="server" TextMode="Number"

MaxLength="1"></asp:TextBox>

</li>

<li>

<asp:Label ID="lblComments" runat="server"

AssociatedControlID="Multi">Comments</asp:Label>

<asp:TextBox runat="server" ID="Multi" TextMode="Multiline"

Rows="5" Columns="30"></asp:TextBox>

</li>

</ol>

<asp:Button ID="Submit" runat="server" CommandName="Submit" Text="Submit" />

</fieldset>

注意,我使用 Opera 浏览器来呈现反馈表单,因为在撰写本文时,它对新的输入类型提供了最好的支持。我将在这一章的后面详细解释。可以从 www.opera.com 下载歌剧。Chrome 对这些功能也有很好的支持。

Save the changes and press F5 to display the new page in the browser. Figure 2-9 shows the feedback form as rendered by the Opera browser.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-9。

The initial feedback form

查看新的输入类型

现在让我们看看每一种新的输入类型,看看它们是如何在 Opera 中实现的。请记住,不同的浏览器可能会以不同的方式呈现控件。

统一资源定位器

第一个字段使用url输入类型,它需要一个有效的 web 地址。如果您输入了无效的地址,当页面被提交时,您将会看到如图 2-10 所示的验证错误

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-10。

The URL field Note

URL 中需要协议,如http://。例如,如果您输入 www.apress.com 并尝试提交表单,该地址将被视为无效。输入 http://www.apress.com改为

选择列表

下一个字段提供了可用浏览器的下拉列表。在 ASP.NET,这被编码为一个包含许多元素的DropDownList。生成的 HTML 使用了一个包含option元素的select元素,如下所示:

<select name="Options" id="Options">

<option value="1">Internet Explorer</option>

<option selected="selected" value="2">Google Chrome</option>

<option value="3">Firefox</option>

<option value="4">Opera</option>

</select

注意,选中的项目用selected属性表示。这是一个布尔值,不需要值。Visual Studio 将显示一个警告,生成的标记将值设置为selected。浏览器将忽略该值,只寻找是否存在selected属性。

日期/时间字段

反馈表单包含以下日期/时间字段,展示了浏览器对各种日期类型字段的支持:

  • 生日:(日期)单一日期(无时间部分)
  • 最喜欢的月份:(Month)整月,包括一年
  • 最忙的一周:(Week)整整一周,包括一年
  • 开始日期/时间:(DateTime)包含时间部分的单个日期
  • 当前时间:(Time)没有日期的时间

日期字段是文本框,您可以在其中键入所需的值,但具有内置的智能。例如,转到生日字段并键入 7,光标将自动转到日期的日部分。如果您键入 1,您将需要输入 0、1 或 2 来完成月份输入,或者只需按 Tab 移动到日期。

还有一个显示日期选择器控件的图标。该控件的不同格式(日期、月份和星期)分别如图 2-11 、 2-12 和 2-13 所示。这些控件本质上是相同的,只是月和周版本只允许您选择整个月或周。请注意,周格式还显示周数(从 1 到 52)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-13。

The date picker selecting an entire week

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-12。

The date picker selecting an entire month

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-11。

The date picker control

开始日期/时间和当前时间字段都包括一个时间控件,允许分别输入小时和分钟,如图 2-14 所示。您也可以使用向上/向下箭头来增加小时或分钟部分,这取决于当前的焦点。但是没有可以选择小时或分钟的下拉菜单。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-14。

The time control Caution

在撰写本文时,ASP.NET 同时支持DateTimeDateTimeLocal文本模式。这些被翻译成 HTML 类型datetimedatetime-local。然而,datetime已经被弃用,取而代之的是datetime-local。所以,一定要在表单中使用DateTimeLocal文本模式。

电话

反馈表单包括一个使用新的tel输入类型的电话字段。在撰写本文时,没有一种桌面浏览器支持这种类型。我把它包括在练习中,希望当你读到这篇文章时,你已经有一个支持它的浏览器了。与所有不支持的类型一样,浏览器将其视为标准的TextBox控件。

范围

下一个控件使用类似于汽车中的燃油表,其中特定值不如相对值重要,例如新范围输入类型。这允许您在控件范围内滑动指示器,提供相对值,如四分之三满。我把这个定义为宽度 300,高度 30。

您可以在 HTML 中操作 range 控件的其他一些属性,但 ASP.NET 不支持这些属性。您仍然可以在。页面,它们会像placeholder属性一样被传递给生成的 HTML。然而,在本章的后面我将向你展示另一种配置范围控制的方法。

颜色

颜色控制包括一个显示选定颜色的小矩形。如果你点击这个,你可以从颜色选择器中选择一种颜色,如图 2-15 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-15。

The color-picker control

数字

“总体评分”字段使用数字输入类型。一些浏览器现在包括上下箭头,允许你增加和减少当前值。提交表单时,如果输入了非数字值,则会显示错误,如图 2-16 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-16。

A non-numeric value error

文本区域

最后一个字段使用文本区域输入类型。我指定使用 5 行 30 列。这只会影响字段在页面上的显示方式。文本存储为单个字符串。文本将被换行以适应页面上分配的大小,但它可以包含任意数量的行。

查看表单

图 2-17 显示了一个完整的表格。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-17。

The completed feedback form

浏览器试图聪明地对适当字段的内容进行拼写检查。请注意,在注释字段中,拼写错误的单词带有下划线。您可以使用spellcheck属性明确地打开或关闭它。要禁用拼写检查,请在此处添加以粗体显示的代码:

<asp:TextBox runat="server" ID="Multi" TextMode="Multiline"

Rows="5" Columns="30"``spellcheck="false"

在每个字段中输入值后,单击 Submit 按钮,然后查看页面的源代码。每个字段现在都有一个value属性,其中包含提交页面时包含的值。这是服务器端代码用来存储和/或处理提交数据的内容。我提取了其中的一部分,如清单 2-3 所示。看看各种日期/时间字段值是如何格式化的。这些以粗体显示。另外,请注意,颜色是以所选 RGB 值的十六进制表示形式存储的。

Listing 2-3. The Source with Submitted Values

<li>

<label for="URL" id="lblURL">Default home page</label>

<input name="URL" type="url"``value="http://www.apress.com"

</li>

<li>

<label for="Options" id="lblOptions">Default browser</label>

<select name="Options" id="Options">

<option value="1">Internet Explorer</option>

<option value="2">Google Chrome</option>

<option value="3">Firefox</option>

<option selected="selected"``value="4"

</select>

</li>

<li>

<label for="Birthday" id="lblBirthday">Birthday</label>

<input name="Birthday" type="date"``value="1995-03-17"

</li>

<li>

<label for="Month" id="lblMonth">Favorite Month</label>

<input name="Month" type="month"``value="1999-07"

</li>

<li>

<label for="Week" id="lblWeek">Busiest Week</label>

<input name="Week" type="week"``value="2015-W14"

</li>

<li>

<label for="DateTime" id="lblStart">Start Date/Time</label>

<input name="DateTime" type="datetime-local"

value="2014-06-14T14:30" id="DateTime" />

</li>

<li>

<label for="Time" id="lblTime">Current Time</label>

<input name="Time" type="time"``value="09:52"

</li>

<li>

<label for="Phone" id="lblPhone">Phone</label>

<input name="Phone" type="tel"``value="800 555-1212"

</li>

<li>

<label for="Range" id="lblRange">Overall satisfaction</label>

<input name="Range" type="range"``value="76"

style="height:30px;width:200px;" />

</li>

<li>

<label for="Color" id="lblColor">Preferred color</label>

<input name="Color" type="color"``value="#ffbe7d"

</li>

<li>

<label for="Score" id="lblScore">Overall Rating</label>

<input name="Score" type="number"``value="8"

</li>

<li>

<label for="Multi" id="lblComments">Comments</label>

<textarea name="Multi" rows="5" cols="30" id="Multi">

This is a multi-line input box with 5 rows and 30 columns.

Notice my spellling mistake is underlined.

</textarea>

</li>.

使用 html 5 测试网站

我提到过我们在这个练习中使用 Opera。每个浏览器可以实现 HTML5 特征的不同子集。上一章提到的网站是一个非常有用的工具,可以帮助你找出哪种浏览器最适合某个特定的功能。

如果您转到“比较”选项卡,您可以选择多达五种不同的浏览器来查看每个功能的并排比较。例如,我选择了 Opera、Google Chrome、Firefox、IE 和 Safari 来查看它们的表单特性。结果显示在图 2-18 中。Opera 和 Chrome 在支持表单方面要先进得多。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-18。

A side-by-side comparison of Opera, Chrome, Firefox, IE, and Safari

使用该网站的另一种方法是查看所有浏览器如何支持特定功能。在“功能”子选项卡(在“比较”选项卡中)中,您可以选择最多三个特定的功能来查看哪些浏览器支持它。我们选择了与range输入类型相关的三个特征,如图 2-19 所示。目前,Chrome 和 Opera 是唯一完全支持这些功能的桌面浏览器。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-19。

Viewing each browser’s support of the range control Caution

这些比较和分析仅供演示之用。浏览器支持正以相当快的速度变化,当你读到这篇文章时,你可能会有不同的结果。但是,比较浏览器支持的方法仍然有效。

使用范围控制

范围控件支持允许您配置其行为的属性。例如,当滑块位于控件的两端时,您可以指定定义字段的valueminmax属性。您还可以指示step属性,该属性控制滑块在标尺上可以停止的位置。例如,如果min为 0,max为 100,step为 20,控制将只允许您以 20 的增量停止(例如,0、20、40、60、80 和 100)。

您可以用 HTML 编写这样的代码:

<!DOCTYPE html>

<input name="Range" type="range" id="Range"

min="0" max="200" step="20"

style="height:30px;width:200px;" />

即使 IntelliSense 不支持这些属性,您也可以在。页面,它们将被包含在最终的 HTML 中。另一种方法是在使用 JavaScript 加载页面时修改控件。

修改步骤属性

现在,您将编写一个简单的脚本来配置范围属性。

EXERCISE 2-3. MODIFYING THE RANGE CONTROLLoad the Chapter 2 project in Visual Studio and open the Feedback.aspx page.   Inside the head tag, add the following script element shown in bold:

<head runat="server">

<title></title>

<script type="text/javascript">

function configureRange() {

var range = document.getElementById("Range");

range.min = 0;

range.max = 200;

range.step = 20;

}

</script>

</head>

This simple JavaScript function modifies the attributes of the range control. The document property represents the HTML document of the current page. The getElementById() function is a selector that returns the specified element, the range control in this case. (I will cover selectors in JavaScript in more detail in Chapter 5.)   Now that the function has been implemented, you need to tell the page to execute it. To do that, add the following code in bold to the <body> tag:

<body``onload="configureRange()"

<form id="form1" runat="server">

This instructs the page to call the configureRange() function when the OnLoad event occurs.   Save your changes and press F5 to load the page.   The range control will look just like it did before, but when you move the slider, it will stop only at the preset values.

添加自定义刻度线

Opera 以前的版本会显示刻度线来帮助分级范围控制,但是现在的版本没有,Chrome 也没有。但是,您可以使用datalist标签自己添加这些内容。截至本文撰写之时,Firefox 还不支持这一特性。

EXERCISE 2-4. ADDING CUSTOM TICK MARKSAdd the following anywhere inside the fieldset tag. This defines the list of values where the tick marks should be placed.

<datalist id="ticks">

<option>0</option>

<option>20</option>

<option>40</option>

<option>60</option>

<option>80</option>

<option>100</option>

<option>120</option>

<option>140</option>

<option>160</option>

<option>180</option>

<option>200</option>

</datalist>

In the Range control, add the list attribute shown in bold. This specifies the datalist tag that defines where the tick marks should be.

<asp:Label ID="lblRange" runat="server"

AssociatedControlID="Range">Overall satisfaction</asp:Label>

<asp:TextBox runat="server" ID="Range" TextMode="Range"

Width="200" Height="30"``list="ticks"

Save your changes and press F5 to display the modified form.   You should see tick marks at each step, as shown in Figure 2-20.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2-20。

The Range control with tick marks

显示范围值

当你在使用Range控件时,我将向你展示一个简单的技巧来显示它的值。您将在范围控件旁边添加一个TextBox控件,然后使用 JavaScript 在范围控件被修改时更新它的值。

Note

当用户移动范围控件时,Internet Explorer 11 会自动显示该控件的当前值。这是每个浏览器如何以不同方式实现功能的一个例子。

EXERCISE 2-5. DISPLAYING THE RANGE VALUEIn the Feedback.aspx page, add the following code in bold to the range item:

<li>

<asp:Label ID="lblRange" runat="server"

AssociatedControlID="Range">Overall satisfaction</asp:Label>

<asp:TextBox runat="server" ID="Range" TextMode="Range"

Width="200" Height="30" list="ticks"></asp:TextBox>

<asp:TextBox runat="server" ID="RangeValue" Width="50"></asp:TextBox>

</li>

Next, add the code in bold to the script section:

<script type="text/javascript">

function configureRange() {

var range = document.getElementById("Range");

range.min = 0;

range.max = 200;

range.step = 20;

updateRangeValue();

}

function updateRangeValue() {

document.getElementById("RangeValue").value

= document.getElementById("Range").value;

}

</script>

The updateRangeValue() function takes the current value of the Range control and stores it in the text box. Also, the configureRange() function that is called when the page is loaded calls updateRangeValue() to set its initial value.   Now you’ll need to call the updateRangeValue() function whenever the range control is updated. To do that, add the code in bold to the Page_Load() event handler in the Feedback.aspx.cs code-behind file.

public partial class Feedback : System.Web.UI.Page

{

protected void Page_Load(object sender, EventArgs e)

{

Range.Attributes.Add("onChange", "updateRangeValue()");

}

}

Save your changes and execute the page. As you move the slider, the selected value is displayed. Notice that it is updated in increments of 20 (if the step attribute is still set at 20).

摘要

在本章中,您使用 Visual Studio 提供的模板创建了一个基本的 ASP.NET web 窗体应用。在简单尝试了 email 控件之后,您创建了一个反馈页面,演示了许多其他输入类型。使用一些简单的 JavaScript,您配置了范围控件并提供了其值的实时显示。

同时,我还提供了一些关于开发环境的有用信息,包括以下内容:

  • 配置浏览器进行测试
  • 在 Internet Explorer 中检查页面元素
  • 使用HTML5Test.com网站研究浏览器支持

三、MVC Web 应用

在这一章中,你将使用 ASP.NET MVC 来创建一个反馈表单,展示几个新的输入类型。我将首先简要介绍。NET 平台,然后向您展示如何使用 MVC 构建一个基于 HTML5 的 web 页面。最终结果将类似于你在第二章中所做的事情,但是实现将会非常不同。正如您将看到的,该解决方案将非常依赖于扩展 MVC 框架以包含新的 HTML5 特性的能力。

模型-视图-控制器是一种架构模式,早在 20 世纪 70 年代就已经存在了。这种模式的主要好处是分离关注点,允许独立开发、测试和维护每一个关注点。模型提供了数据和业务逻辑。例如,如果应用显示产品目录,模型将提供产品细节。如果进行了更改,当控制器调用时,模型负责持久化数据。视图提供了用户体验,既格式化了数据的表示,又使用户能够与输入控件、按钮和链接进行交互。控制器处理用户请求,将其传递给模型并调用适当的视图。图 3-1 说明了这一过程。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-1。

The MVC architectural pattern

介绍 ASP.NET MVC 6

ASP.NET MVC 是一个基于。NET 于 2009 年首次发布,实现了 MVC 模式。最初的版本使用相同的。传统 ASP.NETframework 中使用的 Web Forms 语法。2010 年,发布了一个名为 Razor 的新视图引擎,它以更自然、类似 HTML 的语法生成网页。此外,Razor 引擎允许代码包含在标记文件中,而不是代码隐藏文件。Visual Studio 2015 版本中包含的 MVC 版本 6 将许多实现堆栈与 Web 表单和 Web API 合并在一起。

和我在前一章讨论的传统 ASP.NET Web 表单一样,MVC6 不支持许多现成的新 HTML5 标签。然而,MVC 框架更具可扩展性,这使得添加 HTML5 支持相对容易。在这一章中,我将解释不同的技术来扩展 MVC 框架以包含新的 HTML5 特性。还有几个开源扩展可以安装,我也将简要演示其中的一个。

创建 ASP.NET MVC 项目

在本章中,你将使用 Visual Studio 2015 中的标准模板创建一个 ASP.NET MVC 项目。启动 Visual Studio 2015。在 Web 类别中,选择 ASP.NET Web 应用模板,输入第三章作为项目名称,选择合适的位置,如图 3-2 所示。单击“确定”按钮继续。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-2。

Selecting the ASP.NET Web project

这与您在上一章中创建项目的方式相同。但是,在下一个对话框中,选择 MVC 模板,如图 3-3 所示。这将创建一个 web 应用,看起来就像《??》第二章中的项目,但是它是使用 MVC 风格实现的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-3。

Selecting the MVC template

创建项目后,您将在解决方案资源管理器中看到许多文件夹。注意,控制器、模型和视图都有单独的文件夹,如图 3-4 所示。该示例项目包括这些项目中每一项的几个示例。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-4。

The initial Solution Explorer window

探索剃刀视角

为了快速演示 Razor 视图语法,您可以查看项目模板提供的现有视图。打开Register.cshtml文件,您可以在Views\Account文件夹中找到它。这实现了注册页面的视图。清单 3-1 显示了页面的主要部分。

Listing 3-1. The Initial Register.cshtml Implementation

<h4>Create a new account.</h4>

<hr />

@Html.ValidationSummary("", new { @class = "text-danger" })

<div class="form-group">

@Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })

<div class="col-md-10">

@Html.TextBoxFor(m => m.Email, new { @class = "form-control" })

</div>

</div>

<div class="form-group">

@Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" })

<div class="col-md-10">

@Html.PasswordFor(m => m.Password, new { @class = "form-control" })

</div>

</div>

<div class="form-group">

@Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" })

<div class="col-md-10">

@Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" })

</div>

</div>

<div class="form-group">

<div class="col-md-offset-2 col-md-10">

<input type="submit" class="btn btn-default" value="Register" />

</div>

</div>

在 Razor 语法中,@表示后面的文本是代码而不是文字标记。代码将在运行时生成 HTML 内容。您会注意到大部分代码都使用了Html类。这是一个帮助器类,具有生成 HTML 标记的方法。例如,LabelFor()方法生成标记来插入一个Label控件。

对于表单中的每个字段,代码使用了Html助手类的LabelFor()TextBoxFor()方法。(密码字段使用PasswordFor()方法。)这些方法中的每一个都采用一个 lambda 表达式(例如,m => m.Email)来指定相关模型中的数据元素。用于视图的模型由文件顶部的以下指令定义:

@model Chapter``3

如果你看一下AccountViewModels.cs文件,你会发现RegisterViewModel类的定义。这个类有三个公共属性。

  • Email
  • Password
  • ConfirmPassword

这些属性中的每一个都有一些元数据属性,比如用于生成正确的 HTML 的RequiredDataType。我将在本章后面进一步解释这一点。

使用编辑器模板

TextBoxFor()方法将输出一个标准的TextBox控件。要使用新的 HTML5 输入类型,您需要修改这个实现。MVC 框架允许你使用EditorFor()方法来代替TextBoxFor()。这本身不会改变生成的标记,因为默认的EditorFor()实现仍然使用type="text"属性。我将向您展示如何创建一个编辑器模板来覆盖这个默认行为。

EXERCISE 3-1. ADDING AN EDITOR TEMPLATEOpen the Register.cshtml file, which you’ll find in the Views\Account folder.   For the Email field, replace TextBoxFor with EditorFor. The code will look like this: <div class="form-group">     @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })     <div class="col-md-10">         @Html. EditorFor (m => m.Email, new { @class = "form-control" })     </div> </div>   In the Solution Explorer, right-click the Views\Shared folder and choose Add and New Folder. Enter EditorTemplates for the folder name.

注意在本章的后面,我将解释如何为每个属性选择合适的编辑器模板。编辑器模板必须在EditorTemplates文件夹中,MVC 框架才能使用它们。因为这个文件夹被添加到了Views\Shared文件夹中,所以模板对项目中的所有视图都是可用的。你可以在Views\Account文件夹中创建EditorTemplates文件夹。这将使它们对Account文件夹中的所有视图可用,但对其他文件夹(如Home文件夹)不可用。如果您希望Home模板不同于Account模板,这也允许您为每个文件夹创建一组单独的编辑器模板。如果在两个文件夹中有相同的名称,HomeAccount文件夹中的名称将覆盖Shared版本。

Right-click the Views\Shared\EditorTemplates folder and choose Add and View links.   In the Add View dialog box, enter EmailAddress as the view name and make sure all the check boxes are unselected, as shown in Figure 3-5. Click the Add button to create the template.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-5。

Adding the EmailAddress template   This will generate a view page named EmailAddress.cshtml. Delete the entire content and replace it with the following code. This uses the TextBox() method but specifies some additional attributes including type and placeholder. @Html.TextBox("", null, new {     @class = "text-box single-line",     type = "email",     placeholder = "Enter an e-mail address" })   Save your changes and debug the application. By default, the debugger will try to display the page you have open. Open the Register.cshtml file before pressing F5, and that page will be opened in the browser. Go to the Registration page, and you should see the placeholder text displayed in the empty Email field, as shown in Figure 3-6.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-6。

The blank register form   If you look at the page’s source or the Page Inspector, the actual HTML will look similar to this: <input name="Email"        class="text-box single-line"        id="Email"        type="email"        placeholder="Enter an e-mail address"        value=""        data-val-required="The Email field is required."        data-val-email="The Email field is not a valid e-mail address."        data-val="true" >   Close the browser and stop the debugger.   Tip

和前一章一样,我将使用 Opera 浏览器进行大部分练习,因为它对新的输入类型有最好的支持。

注意生成的标记中的data-val标签。它们用于控制客户端验证逻辑。

ATTRIBUTE DRIVEN VALIDATION

ASP.NET MVC 中的数据验证从模型开始。如果您查看AccountViewModel.cs文件,您会看到附加到每个属性的元数据属性,比如Required。例如,Email属性如下所示:

[Required]

[EmailAddress]

[Display(Name = "Email")]

public string Email { get; set; }

TextBoxFor()助手函数使用元数据属性生成 HTML,就像您看到的电子邮件字段一样。具体来说,生成了data-valdata-val-required HTML 属性。该视图还包括以下 jQuery 库:

<script src="∼/Scripts/jquery.validate.js"></script>

<script src="∼/Scripts/jquery.validate.unobtrusive.js"></script>

这些 JavaScript 库使用 HTML 属性如data-val来执行客户端验证。更多信息,请参见 www.datahaunting.com/mvc/client-and-server-side-validation-using-dataannotation-in-mvc 一文。

添加反馈页面

现在,您将创建一个反馈表单,并使用它来演示如何实现新的 HTML5 功能。您将首先创建一个模型,然后基于该模型实现一个强类型视图。然后,您将添加一个控制器动作以及一个到新页面的链接。

Tip

向 web 应用添加页面通常涉及添加模型、添加视图以及创建或修改控制器。MVC 模式允许分别开发这些视图和模型,在大型项目中,通常会有不同的人负责视图和模型。您可以使用现有的模型。然而,在像这样的小项目中,你是唯一的开发者,你通常需要接触所有三个区域来添加一个页面。

创建反馈模型

模型定义了可以包含在页面中的数据元素。通过首先设计模型,您可以简化视图实现。

在解决方案资源管理器中,右键单击Models文件夹,选择 Add and Class,并输入 FeedbackModel.cs 作为类名。单击“确定”按钮创建该类。对于类的实现,输入清单 3-2 中所示的代码。

Listing 3-2. The FeedbackModel Class

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.ComponentModel.DataAnnotations;

namespace Chapter``3

{

public class FeedbackModel

{

[Display(Name = "Name", Prompt = "Enter your full name"),

Required]

public string Name { get; set; }

[Display(Name = "Average Score", Prompt = "Your average score"),

Range(1.0, 100.0),

Required]

public decimal Score { get; set; }

[Display(Name = "Birthday"),

DataType(DataType.Date)]

public DateTime? Birthday { get; set; }

[Display(Name = "Home page", Prompt = "Personal home page"),

DataType(DataType.Url),

Required]

public string Homepage { get; set; }

[Display(Name = "Email", Prompt = "Preferred e-mail address"),

DataType(DataType.EmailAddress),

Required]

public string Email { get; set; }

[Display(Name = "Phone number", Prompt = "Contact phone number"),

DataType(DataType.PhoneNumber),

Required]

public string Phone { get; set; }

[Display(Name = "Overall Satisfaction")]

public string Satisfaction { get; set; }

}

}

Note

视图文件使用 Razor 语法并有.cshtml(或。vbhtml)分机。然而,模型和控制器文件是标准的 C#(或 VB)类。

重新构建应用。这将使模型在定义视图时可用。

定义反馈视图

现在您将基于这个模型定义一个新的视图。最初,这将是一个具有单个字段的简单表单。然后,您将在主页上添加一个链接和一个控制器操作来处理这个问题。在本章的后面,您将向表单添加更多的字段。

EXERCISE 3-2. DESIGNING THE INITIAL FEEDBACK FORMIn the Solution Explorer, expand the Views folder. Right-click the Home folder and choose Add and View. Enter the name Feedback, select the Empty template, and select the FeedbackModel, as shown in Figure 3-7. Click the Add button to create the view.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-7。

Creating the Feedback view   The new view is generated with a single empty div inside the body tag. Enter the code shown in bold in Listing 3-3. This code includes an input control for the Email property using the EditorFor() method.

清单 3-3。定义初始形式

@model Chapter``3

@{

Layout = null;

}

<!DOCTYPE html>

<html>

<head>

<meta name="viewport" content="width=device-width" />

<title>Feedback</title>

</head>

<body>

<div>

@using (Html.BeginForm((string)ViewBag.FormAction, "Home"))

{

<fieldset>

<legend>Feedback Form</legend>

<div>

@Html.EditorFor(m => m.Email)

</div>

<p>

<input type="submit" value="Submit" />

</p>

</fieldset>

}

</div>

</body>

</html>

Views are invoked by a controller, so you’ll need to add a controller action that will load this page. Open the HomeController.cs class, which you’ll find in the Controllers folder.   Add the following method: public ActionResult Feedback() {     return View(); }   Finally, you’ll need a link that triggers this controller action. Open _Layout.cshtml in the View\Shared folder.   Add the line shown in bold: <ul id="menu">     <li>@Html.ActionLink("Home", "Index", "Home")</li>     <li>@Html.ActionLink("About", "About", "Home")</li>     <li>@Html.ActionLink("Contact", "Contact", "Home")</li>     <li>@Html.ActionLink("Feedback", "Feedback", "Home")</li> </ul>   Save your changes and press F5 to debug. You should now have a Feedback link on the home page, as shown in Figure 3-8.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-8。

The Feedback link on the home page   Click this link to display the feedback form, which is shown in Figure 3-9.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-9。

The initial feedback form   Enter an invalid email address and click the Submit button. You should see the standard HTML5 validation error, as shown in Figure 3-10.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-10。

The standard HTML5 validation error   View the source of the feedback form, which should be similar to this: <form action="/Home/Feedback" method="post">     <fieldset>         <legend>Feedback Form</legend>         <div>             <input class="text-box single-line" data-val="true"                    data-val-required="The Email field is required." id="Email"                    name="Email" placeholder="Enter an e-mail address"                    type="email" value="" />         </div>         <p>             <input type="submit" value="Submit" />         </p>     </fieldset> </form>

填写反馈表

现在,您将把剩余的字段添加到反馈表单中。您还需要为其他数据类型提供编辑器模板。我将向您展示框架如何决定使用哪个模板。

添加其他字段

您将从添加在FeedbackModel.cs类中定义的其他字段开始。对于每一个,您将包含一个标签,并使用EditorFor()方法来生成输入字段。

EXERCISE 3-3. COMPLETING THE FEEDBACK FORMOpen the Feedback.cshtml file and add the code shown in bold in Listing 3-4.

清单 3-4。反馈视图实现

<div>

@Html.EditorFor(m => m.Email)

</div>

<div class="editor-label">

@Html.LabelFor(m => m.Name)

</div>

<div class="editor-field">

@Html.EditorFor(m => m.Name)

</div>

<div class="editor-label">

@Html.LabelFor(m => m.Birthday)

</div>

<div class="editor-field">

@Html.EditorFor(m => m.Birthday)

</div>

<div class="editor-label">

@Html.LabelFor(m => m.Homepage)

</div>

<div class="editor-field">

@Html.EditorFor(m => m.Homepage)

</div>

<div class="editor-label">

@Html.LabelFor(m => m.Phone)

</div>

<div class="editor-field">

@Html.EditorFor(m => m.Phone)

</div>

<div class="editor-label">

@Html.LabelFor(m => m.Score)

</div>

<div class="editor-field">

@Html.EditorFor(m => m.Score)

</div>

<div class="editor-label">

@Html.LabelFor(m => m.Satisfaction)

</div>

<div class="editor-field">

@Html.EditorFor(m => m.Satisfaction)

</div>

<p>

<input type="submit" value="Submit" />

</p>

Save your changes and press F5 to view the modified form. Click the Feedback link to display the page, which will look similar to Figure 3-11.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-11。

The feedback form   Notice that all the new fields, except Birthday, use the standard TextBox control and do not include a placeholder text. This is because there is no editor template defined for these data types. The Birthday property was defined in the model as a DateTime value, and the implementation of the Textbox control uses this placeholder for dates.

添加编辑器模板

你可能一直在问自己,框架如何知道使用哪个编辑器模板?框架会根据属性的数据类型尝试使用正确的模板。这不太可靠,因为电子邮件、URL 和电话号码都存储在一个string变量中。首选方法是使用元数据来定义它。

如果在模型类中包含了System.ComponentModel.DataAnnotations名称空间,那么就可以在模型中包含元数据。有两个元数据属性用于确定适当的模板。

  • DataType
  • UIHint

使用DataType枚举来指定DataType属性。这包括一组相当大但固定的值,比如上下文类型EmailAddressCreditCardCurrencyPostalCodeUrl。如果您添加了一个DataType属性,将使用具有匹配名称的编辑器模板。当您实现FeedbackModel时,您包含了DataType属性。

UIHint属性是用一个字符串指定的,因此您可以使用任何想要的值。如果您希望一个属性以绿色字体显示,您可以在模型中指定UIHint("GreenFont")属性,然后提供一个GreenFont.cshtml模板。在确定要使用的合适模板时,UIHint优先于DataType属性。

Tip

我的GreenFont示例用来说明UIHint属性是如何工作的。您不应该使用它来设置样式属性,因为这是样式表的作用。当你实现一个range控件时,一个更合适的UIHint属性的应用将在本章后面演示。

Right-click the Views\Shared\EditorTemplates folder and choose Add and View. In the Add View dialog box, enter the name Date and unselect all of the check boxes. Replace the view implementation with the following code: @Html.TextBox("", null, new {    @class = "text-box single-line",    type = "date" })   In the same way, add another editor template named Url and use the following implementation: @Html.TextBox("", null, new {    @class = "text-box single-line",    type = "url",    placeholder = "Enter a web address" })   Create a PhoneNumber template using the following code: @Html.TextBox("", null, new {     @class = "text-box single-line",     type = "tel",     placeholder = "Enter a phone number" })   Create a Number template using the following code (you will be using this in a later exercise): @Html.TextBox("", null, new {     @class = "text-box single-line",     type = "number",     placeholder = "Enter a number" })   Save your changes and press F5 to debug your application. The feedback form should now use the HTML5 controls, as shown in Figure 3-12.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-12。

The form using HTML5 controls

生成自定义 HTML

您实现的编辑器模板都基于Html助手类的TextBox()方法。模板只是添加了一些额外的属性,比如typeplaceholder。但是,您可以实现输出任何您想要的 HTML 内容的模板。为了演示这一点,我将向您展示如何构建自己的助手扩展,从头开始生成标记。你将用它来替换EmailAddress模板。

添加自定义助手类

您可以创建自己的助手类,并将其添加为现有Html助手类的属性。然后,您可以按如下方式访问您的自定义方法:

@Html.<CustomClass>.<CustomMethod>()

EXERCISE 3-4. CREATING A HELPER EXTENSIONIn the Solution Explorer, right-click the Chapter3 project and choose Add and Class links. Enter the name Html5.cs when prompted for the class name.   Enter the source shown in Listing 3-5.

清单 3-5。初始 HTML5 助手类

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Globalization;

namespace System.Web.Mvc

{

public class Html5Helper

{

private readonly HtmlHelper htmlHelper;

public Html5Helper(HtmlHelper htmlHelper)

{

this.htmlHelper = htmlHelper;

}

private static CultureInfo Culture

{

get

{

return CultureInfo.CurrentCulture;

}

}

// Add custom methods here...

}

public static class HtmlHelperExtension

{

public static Html5Helper Html5(this HtmlHelper instance)

{

return new Html5Helper(instance);

}

}

}

这里有几件事需要指出。首先,注意名称空间被设置为System.Web.Mvc,而不是你的应用的名称空间Chapter 3 。您的自定义助手类被命名为Html5Helper,它的构造函数带有一个HtmlHelper参数。这是对标准助手类的引用,该类存储为私有类成员。您的定制方法将需要它来从框架中访问数据,如视图和模型信息。最后,这段代码还声明了一个静态的HtmlHelperExtension类,它提供了一个静态方法来返回您的自定义类。注意,方法名是Html5,所以您将从视图中访问您的定制类,如下所示:

@Html.Html5().<CustomMethod>()

拥有自己的自定义助手类的目的是为了能够实现自定义助手方法。所以,现在再加一个。第一种方法将生成一个电子邮件输入控件。然后您将在您的EmailAddress.cshtml模板中使用它。

Add the code shown in Listing 3-6 to your custom class where the // Add custom methods here placeholder is.

清单 3-6。EmailControl 实现

public IHtmlString EmailControl()

{

string id;

string name;

string placeHolder;

string value;

string valueAttribute;

ViewDataDictionary viewData = htmlHelper.ViewData;

ModelMetadata metaData = viewData.ModelMetadata;

// Build the HTML attributes

id = viewData.TemplateInfo.GetFullHtmlFieldId(string.Empty);

name = viewData.TemplateInfo.GetFullHtmlFieldName(string.Empty);

if (string.IsNullOrWhiteSpace(metaData.Watermark))

placeHolder = string.Empty;

else

placeHolder = "placeholder=\"" + metaData.Watermark + "\"";

value = viewData.TemplateInfo.FormattedModelValue.ToString();

if (string.IsNullOrWhiteSpace(value))

valueAttribute = string.Empty;

else

valueAttribute = "value=\"" + value + "\"";

// Determine the css class

string css = "text-box single-line";

ModelState state;

if (viewData.ModelState.TryGetValue(name, out state)

&& (state.Errors.Count > 0))

css += " " + HtmlHelper.ValidationInputCssClassName;

// Format the final HTML

string markup = string.Format(Culture,

"<input type=\"email\" id=\"{0}\" name=\"{1}\" {2} {3} " +

"class=\"{4}\"/>", id, name, placeHolder, valueAttribute, css);

return MvcHtmlString.Create(markup);

}

这个方法收集各种 HTML 属性,比如idnameclassplaceholder。该信息是从模型或模型元数据中提取的。在这个方法的最后,使用标准的string.Format()方法构建了markup字符串,该方法集合了各种属性。然后将它传递给静态的MvcHtmlString.Create()方法,以提供 MVC 框架所需的IHtmlString接口。

这个EmailAddress模板实现的主要区别是占位符属性是使用模型元数据设置的。前面的实现使用了硬编码的占位符“输入电子邮件地址”不幸的是,财产名称完全不一致。在模型中,这是使用Prompt属性(Prompt = "Preferred e-mail address")指定的。在ModelMetadata类中,这个值作为Watermark属性提供。当然,这作为一个placeholder属性包含在 HTML 文档中。

重新实现自定义电子邮件模板

现在您将使用一个更简单的模板替换EmailAddress模板,该模板使用您刚刚实现的新助手扩展。

EXERCISE 3-5. RE-IMPLEMENTING THE E-MAIL TEMPLATESave the changes and open the EmailAddress.cshtml template.   Replace the entire implementation with the following: @Html.Html5().EmailControl()   Save the changes and press F5 to debug. The placeholder text should now reflect the prompt specified in the model metadata, as demonstrated in Figure 3-13.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-13。

The modified Email field   View the source of this page, and the HTML markup for the Email field should look like this: <input type="email"        id="Email"        name="Email"        placeholder="Preferred e-mail address"        class="text-box single-line">

实现范围控制

正如你在前一章看到的,range控件支持一些标准TextBoxFor(甚至是EditorFor)实现中没有的附加属性。为了使用 MVC 框架实现这一点,您将实现一个定制的 helper 方法。然后,您将提供一个调用这个自定义方法的编辑器模板。最后,您将在模型元数据中添加一个UIHint属性,告诉框架使用新的模板。

实现自定义帮助器方法

第一步是创建一个定制的助手方法,它将为一个range控件生成适当的标记。这将类似于您刚刚实现的EmailControl()方法,除了它不包括placeholder属性。此外,minmaxstep属性被传递给该方法。

将清单 3-7 中的代码添加到Html5.cs文件中(在Html5Helper类中)。

Listing 3-7. The RangeControl Implementation

public IHtmlString RangeControl(int min, int max, int step)

{

string id;

string name;

string value;

string valueAttribute;

ViewDataDictionary viewData = htmlHelper.ViewData;

// Build the HTML attributes

id = viewData.TemplateInfo.GetFullHtmlFieldId(string.Empty);

name = viewData.TemplateInfo.GetFullHtmlFieldName(string.Empty);

value = viewData.TemplateInfo.FormattedModelValue.ToString();

if (string.IsNullOrWhiteSpace(value))

valueAttribute = string.Empty;

else

valueAttribute = "value=\"" + value + "\"";

// Determine the css class

string css = "range";

ModelState state;

if (viewData.ModelState.TryGetValue(name, out state)

&& (state.Errors.Count > 0))

css += " " + HtmlHelper.ValidationInputCssClassName;

// Format the final HTML

string markup = string.Format(Culture,

"<input type=\"range\" id=\"{0}\" name=\"{1}\" " +

"min=\"{2}\" max=\"{3}\" step=\"{4}\" {5} class=\"{6}\"/>",

id, name, min.ToString(), max.ToString(), step.ToString(),

valueAttribute, css);

return MvcHtmlString.Create(markup);

}

添加范围模板

现在您需要为range控件创建一个编辑器模板,它将使用这个新的定制方法。

EXERCISE 3-6. ADDING A RANGE TEMPLATERight-click the Views\Shared\EditorTemplates folder and choose Add and View.   In the Add View dialog box, enter the name Range and unselect all of the text boxes.   Replace the default implementation with the following: @Html.Html5().RangeControl(0, 200, 20)   Open the FeedbackModel.cs file and add the UIHint attribute to the Satisfaction property like this: [Display(Name = "Overall Satisfaction") , UIHint("Range") ] public string Satisfaction { get; set; }   While you have the FeedbackModel.cs file open, add a UIHint attribute for the Score property as follows: [Display(Name = "Average Score", Prompt = "Your average score"), Range(1.0, 100.0), UIHint("Number"), Required] public decimal Score { get; set; }   Save your changes and press F5 to debug. Go to the Feedback page; the page should look like Figure 3-14.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-14。

The updated score and range control

使用开源扩展

到目前为止,您已经创建了两个基于定制助手方法的编辑器模板和四个基于TextBox()方法的简单模板。然而,除了这些,你可能还需要一些其他的模板。在你花时间去实现它们之前,你可能想知道是否有人已经为你做了这些。嗯,答案是肯定的。

有许多第三方库和工具可供您使用。Visual Studio 提供了一个名为 NuGet 的包管理器,可以很容易地找到、下载、安装和管理这些第三方包。我将向您展示如何使用 NuGet 来安装一个编辑器模板包,这样您就不必自己编写它们了。当然,现在你已经知道如何写你自己的了,如果其中的任何一个不像你希望的那样工作,你可以自由地这样做。

EXERCISE 3-7. INSTALLING EDITOR TEMPLATESWhen the third-party package is installed, it will prompt you before overwriting any existing templates. So before you begin, you should delete the existing editor templates. Delete all of the files in the EditorTemplates folder except for Range.cshtml (the third-party package does not include this template).   In Visual Studio, with the Chapter3 project still open, choose Tools and NuGet Package Manager and Manage NuGet Packages for Solution.   This will display the Manage NuGet Packages dialog box. If you select Installed in the Filter drop-down, it will list the packages currently installed. You might be surprised to find that quite a few have already been installed by the project template. The blue icon to the right of each package indicates whether there is an update available for it, as demonstrated in Figure 3-15.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-15。

Listing the installed packages   Change the Filter drop-down to All, and enter html5 editor templates in the search field.   Select the package named Html5EditorTemplates, as shown in Figure 3-16. The pane on the right displays details of this package including author, description, and links for more information.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-16。

Selecting the Html5EditorTemplates package   Click the Install button.   Once the install has completed, you should now see quite a few templates in the EditorTemplates folder. Open the EmailAddress.cshtml file. Listing 3-8 shows the third-party implementation for this template. While this is implemented differently from yours, it accomplishes basically the same thing, including getting the placeholder from the metadata.

清单 3-8。开源电子邮件模板

@{

var attributes = new Dictionary<string, object>();

attributes.Add("type", "email");

attributes.Add("class", "text-box single-line");

attributes.Add("placeholder", ViewData.ModelMetadata.Watermark);

//since this is a constraint, IsRequired and other constraints

//won't necessarily apply in the browser, but in case script

//turns off readonly we want the constraints passed

if (ViewData.ModelMetadata.IsReadOnly)

{

attributes.Add("readonly", "readonly");

}

if (ViewData.ModelMetadata.IsRequired)

{

attributes.Add("required", "required");

}

}

@Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, attributes)

Press F5 to debug the Feedback page, which should look like Figure 3-17.

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-17。

The feedback page using third-party templates

添加文本 HTML

使用Html助手类,包括EditorFor()方法,是用 ASP.NET MVC 实现表单的推荐方法。这提供了与模型的紧密集成,包括模型元数据和关注点的分离(业务规则和用户体验)。但是,您总是可以在视图中嵌入实际的 HTML 标记。一个合适的用法是包含静态内容或没有连接到模型的控件,比如进度条。

我现在将演示三个例子,每个例子都使用直接 HTML 标记将一个新的 HTML5 控件插入到反馈表单中。

  • 范围
  • 进步

添加范围控件

您已经使用自定义编辑器模板包含了一个range控件。现在,您将通过简单地添加适当的 HTML 标记来插入另一个。出于好玩,您将通过将变换设置为旋转 90 度,使其成为垂直滑块。为此,将清单 3-9 中粗体显示的代码添加到Feedback.cshtml视图中。

Caution

如果高度大于宽度,Opera 以前的版本会垂直呈现一个range控件。当前版本(在撰写本文时)没有做到这一点。在如何实现这一点上,浏览器实现之间似乎没有什么共识。我发现使用transform属性是实现这一点的最一致的方式。我将在第四章的中更详细地解释转换。

Listing 3-9. Adding a range Control in HTML

<fieldset>

. . .

<div class="editor-label">

@Html.LabelFor(m => m.Satisfaction)

</div>

<div class="editor-field">

@Html.EditorFor(m => m.Satisfaction)

</div>

<div>

Custom range

<input type="range" id="CustomRange" name="CustomRange"

class="range"

style="width: 100px; height: 30px; transform: rotate(90deg)"

min="0" max="200" step="20" />

</div>

<p>

<input type="submit" value="Submit" />

</p>

</fieldset>

保存您的更改,然后按 F5 进行调试。该表格应如图 3-18 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-18。

Adding a vertical range control Note

该控件的值不是模型的一部分,不会与表单一起保存。如果控件仅用于帮助用户体验,并且不需要保持,这是合适的。例如,它可以控制视频或音频剪辑的音量。

添加进度条

接下来,您将通过在表单中插入一个progress标签来添加一个进度条。在提交按钮后添加以下粗体代码:

<p>

<input type="submit" value="Submit" />

</p>

<div>

<progress id="FormProgress" value="60" max="100">

<strong>Progress: 60%</strong>

</progress>

</div>:

</fieldset>

进度标签不支持min属性,只支持max属性。最小值被假定为零。value属性指定了当前的进度。按 F5 调试应用并导航到反馈表单。进度应如图 3-19 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-19。

The progress control in Opera

标签内的内容用于不支持标签的浏览器。例如,在 IE9 中,表单看起来如图 3-20 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-20。

The progress control in IE9

更新进度条

但是,一个静态的进度条不是很有趣;人们甚至会发现一个进度条,它永远不会变得令人沮丧。现在,您将添加一些 JavaScript 代码,以便在表单上的字段被输入时更新进度条。

首先,您将创建一个名为calculateProgress()的函数,它遍历所有输入字段,查看哪些字段有值。有六个字段,因此您将为每个字段赋值 17 (6 × 17 = 102)。将该值设置为任何大于 100 的值都会显示为 100%完成。这段代码使用了document.getElementsByClassName()选择器,它返回具有指定 class 属性的所有元素。在这种情况下,您需要具有text=box single-line类的元素。然后,该函数使用计算出的值更新进度条的值。

然后,每当输入字段发生变化时,您都需要调用这个函数。为此,您将创建一个名为bindEvents()的函数,并使用同一个getElementsByClassName()选择器。这一次,您将使用addEventListener()函数将calculateProgress()函数绑定到onChange事件。最后,您将调用onLoad事件处理程序中的bindEvents()函数。

将列表 3-10 中的粗体代码输入反馈表。

Listing 3-10. Adding JavaScript to Update the Progress Bar

<head>

<meta name="viewport" content="width=device-width" />

<title>Feedback</title>

<script type="text/javascript">

function calculateProgress() {

var value = 0;

var fieldList = document.getElementsByClassName("text-box single-line");

for (var i = 0; i < fieldList.length; i++) {

if (fieldList[i].value > "")

value += 17;

}

if (value > 100)

value = 100;

var progress = document.getElementById("FormProgress");

progress.value = value;

};

function bindEvents() {

var fieldList = document.getElementsByClassName("text-box single-line");

for (var i = 0; i < fieldList.length; i++) {

fieldList[i].addEventListener("change", calculateProgress, false);

}

}

</script>

</head>

<body``onload="bindEvents();"

Note

在计算进度时,这段代码忽略了用于Satisfaction字段的range控件以及总分数。这样做是因为这些控件总是有一个值,所以你不能告诉一个值是什么时候“输入”的

此外,将progress标签的初始值属性从 60 更改为 0,如下所示:

<progress id="FormProgress" value=``"0"

按 F5 调试应用。当您在输入字段中输入值时,请注意进度条会自动更新,如图 3-21 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-21。

The progress and range controls in Chrome Tip

正如我提到的,当浏览器不支持progress控件时,会显示progress标签中的文本。您可以用 JavaScript 动态更新它;但是,如果不支持,您也可以将其留空,不显示进度。

使用仪表控制

对于最后一个示例,您将添加一个仪表控件,它类似于进度条。血糖仪允许您在启用状态指示器颜色编码的范围内定义间隔。例如,考虑汽车上的油压表。“正常”范围显示在仪表上,低值或高值突出显示。我不需要知道油压是多少,甚至不需要知道油压应该是多少;我只想知道是否在正常范围内。

range控件一样,meter控件支持minmax属性以及当前的value。它还提供了定义正常范围的lowhighoptimum属性。以粗体输入以下代码:

<div>

<progress id="FormProgress" value="0" max="100">

<strong>Progress: 60%</strong>

</progress>

</div>

<div>

<meter id="Meter" value="50" min="20" max="120"

low="50" high="100" optimum="75">

<strong>Meter:</strong>

</meter>

</div>

</fieldset>

为了演示不同的值是如何显示的,您将添加一些 JavaScript 代码,每秒钟用一个随机值更新控件。为此,将以下粗体代码添加到bindEvents()函数中:

function bindEvents() {

var fieldList = document.getElementsByClassName("text-box single-line");

for (var i = 0; i < fieldList.length; i++) {

fieldList[i].addEventListener("change", calculateProgress, false);

}

setInterval(function () {

var meter = document.getElementById("Meter");

meter.value = meter.min + Math.random() * (meter.max - meter.min);

}, 1000);

}

这段代码使用了setInterval()函数,所以每隔 1000 毫秒就调用一次匿名函数。按 F5 启动应用。根据数值的不同,颜色会由绿色变为黄色,如图 3-22 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-22。

The meter control

摘要

如果你已经迷失在各种更新中,清单 3-11 展示了Feedback.cshtml视图的完整实现。

Listing 3-11. The Final Feedback.cshtml Implementation

@model Chapter``3

@{

Layout = null;

}

<!DOCTYPE html>

<html>

<head>

<meta name="viewport" content="width=device-width" />

<title>Feedback</title>

<script type="text/JavaScript">

function calculateProgress() {

var value = 0;

var fieldList = document.getElementsByClassName("text-box single-line");

for (var i = 0; i < fieldList.length; i++) {

if (fieldList[i].value > "")

value += 17;

}

if (value > 100)

value = 100;

var progress = document.getElementById("FormProgress");

progress.value = value;

};

function bindEvents() {

var fieldList = document.getElementsByClassName("text-box single-line");

for (var i = 0; i < fieldList.length; i++) {

fieldList[i].addEventListener("change", calculateProgress, false);

}

setInterval(function () {

var meter = document.getElementById("Meter");

meter.value = meter.min + Math.random() * (meter.max - meter.min);

}, 1000);

}

</script>

</head>

<body onload="bindEvents();">

<div>

@using (Html.BeginForm((string)ViewBag.FormAction, "Home"))

{

<fieldset>

<legend>Feedback Form</legend>

<div>

@Html.EditorFor(m => m.Email)

</div>

<div class="editor-label">

@Html.LabelFor(m => m.Name)

</div>

<div class="editor-field">

@Html.EditorFor(m => m.Name)

</div>

<div class="editor-label">

@Html.LabelFor(m => m.Birthday)

</div>

<div class="editor-field">

@Html.EditorFor(m => m.Birthday)

</div>

<div class="editor-label">

@Html.LabelFor(m => m.Homepage)

</div>

<div class="editor-field">

@Html.EditorFor(m => m.Homepage)

</div>

<div class="editor-label">

@Html.LabelFor(m => m.Phone)

</div>

<div class="editor-field">

@Html.EditorFor(m => m.Phone)

</div>

<div class="editor-label">

@Html.LabelFor(m => m.Score)

</div>

<div class="editor-field">

@Html.EditorFor(m => m.Score)

</div>

<div class="editor-label">

@Html.LabelFor(m => m.Satisfaction)

</div>

<div class="editor-field">

@Html.EditorFor(m => m.Satisfaction)

</div>

<div>

Custom range

<input type="range" id="CustomRange" name="CustomRange"

class="range vertical"

style="width: 100px; height: 30px; transform: rotate(90deg)"

min="0" max="200" step="20" />

</div>

<p>

<input type="submit" value="Submit" />

</p>

<div>

<progress id="FormProgress" value="0" max="100">

<strong>Progress: 0%</strong>

</progress>

</div>

<div>

<meter id="Meter" value="50" min="20" max="120"

low="50" high="100" optimum="75">

<strong>Meter:</strong>

</meter>

</div>

</fieldset>

}

</div>

</body>

</html>

在这一章中,你在 ASP.NET MVC 项目中使用了一些新的 HTML5 输入类型。与传统的 Web 表单项目一样,您必须做一些额外的工作来使用它们,但是合并新的 HTML5 特性是相当容易的。特别是,MVC 框架被设计成可扩展的,这为构建 HTML5 应用提供了一个干净的平台。

MVC 模式提供了定义表单上使用的数据元素的模型。通过在模型中包含一些元数据属性,然后提供定制模板,您可以利用 HTML5 语义特定的控件。您可以下载并安装开源扩展,从而轻松构建符合 HTML5 的应用。然而,在这一章中,我向你展示了如何构建你自己的自定义助手扩展和编辑器模板。如果您发现自己处于一种独特的情况,需要一个特定的实现,那么您总是可以构建自己的实现。

使用 MVC Razor 视图引擎,您还可以包含文字 HTML 标记,这样您就可以最终控制用户体验。我还介绍了两个新的 HTML 控件,progressmeter,并演示了如何通过一些简单的 JavaScript 操作它们。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值