jQueryMobile-Web-开发基础知识-全-

jQueryMobile Web 开发基础知识(全)

原文:zh.annas-archive.org/md5/9E8057489CB5E1187C018B204539E747

译者:飞龙

协议:CC BY-NC-SA 4.0

序言

什么是 jQuery Mobile?

在将近两年之前的 2010 年 8 月 11 日,John Resig(jQuery 的创建者)宣布了 jQuery Mobile 项目。虽然重点是 UI 框架,但这也是对 jQuery 本身作为移动网站工具的认可,以及将对核心框架本身进行工作,使其在设备上运行更顺畅。随着版本的发布,jQuery Mobile 项目逐渐演变成一个强大的框架,每次更新都融合了更多的平台、更多的功能和更好的性能。

但是当我们说 UI 框架 时,我们是指什么?这对开发人员和设计师意味着什么?jQuery Mobile 提供了一种将常规 HTML(和 CSS)转换为移动友好站点的方法。正如您将很快在第一章中看到的,您可以取一个常规的 HTML 页面,加入 jQuery Mobile 所需的部分(基本上是五行 HTML),然后发现您的页面立即转变为移动友好版本。

与其他框架不同,jQuery Mobile 专注于 HTML。事实上,作为与 jQuery 绑定的框架,您可以在不写一行 JavaScript 的情况下完成大量工作。这是一种强大、实用的创建移动网站的方式,任何现有 HTML 开发人员都可以在几小时内掌握并调整。将此与其他框架进行比较,比如 Sencha Touch。Sencha Touch 也是一个强大的框架,但其方法与众不同,使用 JavaScript 来帮助定义和布局页面。jQuery Mobile 对于熟悉 HTML 而不是 JavaScript 的人更加友好。jQuery Mobile 是触摸友好的,这对于任何曾经使用过智能手机并苦于在网站上点击准确位置的人都是有意义的。对于任何无意中点击重置按钮而不是提交按钮的人也是有意义的。jQuery Mobile 将增强您的内容以帮助解决这些问题。常规按钮变成了大、厚实且易于点击的按钮。链接可以转变为基于列表的导航系统。内容可以分割成具有平滑动画效果的虚拟页面。您会惊讶地发现,jQuery Mobile 几乎不需要编写代码就能工作得很好。

jQuery Mobile 有一些非常大的赞助商。它们包括诺基亚、黑莓、Adobe 和其他大公司。这些公司投入了资金、硬件和开发资源,以帮助确保该项目的成功:

什么是 jQuery Mobile?

成本是多少?

啊,百万美元问题。幸运的是,这个问题很容易回答:什么也不需要。像 jQuery 本身一样,jQuery Mobile 完全免费供任何目的使用。不仅如此,它完全开源。不喜欢某些功能的工作方式?您可以更改它。希望有些框架不支持的功能?您可以添加它。公平地说,深入挖掘代码库可能是大多数人不太愿意做的事情。然而,您需要知道的是,如果有需要,您可以这样做,而其他人也可以这样做,这导致了一个社区可以共同开发的产品。

您需要了解什么?

最后,除了不花一分钱获取并使用 jQuery Mobile 外,最好的事情可能是您可能已经具备了使用该框架所需的所有技能。正如您将在接下来的章节中看到的,jQuery Mobile 是基于 HTML 的框架。如果您了解 HTML,即使只是简单的 HTML,您也可以使用 jQuery Mobile 框架。了解 CSS 和 JavaScript 是一种优势,但并非完全必需的。(虽然 jQuery Mobile 在幕后使用了大量 CSS 和 JavaScript,但您实际上不必自己编写任何内容!)

那么原生应用程序呢?

jQuery Mobile 并不创建原生应用程序。您将在本书后面看到,如何将 jQuery Mobile 与 包装器 技术(如 PhoneGap)结合起来创建原生应用程序,但总的来说,jQuery Mobile 是用于构建网站的。关于开发网站还是移动应用程序的问题并非本书可以回答的。您需要查看您的业务需求并确定哪种方式会满足它们。因为我们不是在构建移动应用程序本身,所以您不必担心在 Google 或 Apple 上设置任何帐户,也不必为市场支付任何费用。任何带有浏览器的移动设备用户都可以查看您的移动优化网站。

再次强调 - 如果您想使用 jQuery Mobile 开发真正的移动应用程序,这绝对是一个选项。

求救!

虽然我们希望这本书涵盖您所有 jQuery Mobile 需要的每一个可能的主题,但很可能会有一些我们无法涵盖的内容。如果您需要帮助,有几个地方您可以尝试。

其次,jQuery Mobile 文档 (jquerymobile.com/demos/1.0/),涵盖了语法、功能和一般开发,与本书类似。虽然内容可能有些重复,但如果您在这里发现有些内容令人困惑,请尝试官方文档。有时,第二个解释确实可以帮助理解。

首先,jQuery Mobile 论坛 (forum.jquery.com/jquery-mobile),是一个开放式讨论列表,讨论 jQuery Mobile 主题。这是提问的完美场所。此外,这也是了解其他人遇到的问题的好地方。您甚至可能能够帮助他们。学习新主题的最佳方式之一就是帮助他人。

例子

想要看看 jQuery Mobile 的实际效果吗?有一个网站可以满足您。JQM Gallery (www.jqmgallery.com/),是用户提交的使用 jQuery Mobile 构建的网站集合。毫不奇怪,这个网站也使用了 jQuery Mobile,这使它成为另一种抽样 jQuery Mobile 的方式:

示例

本书涵盖内容

第一章,准备您的第一个 jQuery Mobile 项目,指导您完成第一个 jQuery Mobile 项目。它详细说明了必须添加到项目目录和源代码中的内容。

第二章,处理 jQuery Mobile 页面,延续了上一章的工作,并介绍了 jQuery Mobile 页面的概念。

第三章,用页眉、页脚和工具栏增强页面,解释了如何使用精美格式化的页眉和页脚增强您的页面。

第四章,列表处理,描述了如何创建 jQuery Mobile 列表视图。这些是移动优化的列表,特别适用于导航。

第五章,实践 —— 构建一个简单的酒店移动网站,引导您创建您的第一个“真实”(尽管简单)的 jQuery Mobile 应用程序。

第六章,处理表单和 jQuery Mobile,解释了使用 jQuery Mobile 优化的表单的过程。布局和特殊表单功能都有详细介绍。

第七章,创建模态对话框、网格和可折叠块,指导您使用 jQuery Mobile 特有的用户界面项目来创建基于网格的布局、对话框和可折叠内容区域。

第八章,jQuery Mobile 配置、工具和 JavaScript 方法,描述了您的代码可能需要的各种基于 JavaScript 的实用工具。

第九章,处理事件,详细说明了由各种 jQuery Mobile 相关功能引发的事件,例如页面加载和卸载。

第十章,进一步操作 Notekeeper 移动应用程序,指导您完成创建另一个网站的过程,一个增强了 HTML5 的笔记应用程序。

第十一章,增强 jQuery Mobile,演示了如何通过选择和创建独特主题来更改您的 jQuery Mobile 站点的默认外观。

第十二章, 创建原生应用,将之前学习的内容进行扩展,说明如何使用开源项目 PhoneGap 创建真正的原生应用。

第十三章, 成为专家 ­ 构建一个 RSS 阅读器应用,通过创建一个可以让您在移动设备上添加和阅读 RSS 订阅的应用,对之前的章节进行了拓展。

您为本书所需的内容

无需什么!技术上您需要一台计算机,还有一个浏览器,但是 jQuery Mobile 是用 HTML、CSS 和 JavaScript 构建的。与框架一同工作时不需要集成开发环境(IDE)或特殊工具。如果您的系统上有任何编辑器(所有操作系统都包括某种免费编辑器),您都可以使用 jQuery Mobile 进行开发。

有一些可以帮助您更加高效的好的集成开发环境。例如,Adobe Dreamweaver CS 5.5 可以原生支持 jQuery Mobile,包括代码辅助和设备预览:

您为本书所需的内容

总的来说,您可以免费使用 jQuery Mobile 进行开发。您可以免费下载、开发和发布 jQuery Mobile 站点。

本书适合人群

本书适用于任何希望拥抱移动开发并将技能扩展到桌面之外的人。

惯例

在本书中,您会发现一些文本样式,用于区分不同类型的信息。以下是这些样式的一些示例,以及它们的含义解释。

文本中的代码词显示如下:"注意到添加到 div 标签的新data-title标签。"

代码块设置如下:

<html>
<head>
<meta name="viewport" content="width=device-width, initial- scale=1">
<title>Multi Page Example</title>

新术语重要单词以粗体显示。屏幕上看到的单词,比如菜单或对话框中出现的单词,如下文所示:"想象一下我们的Megacorp页面。它有三个页面,但产品页面是单独的 HTML 文件。"

注意

警告或重要说明会以这样的方式显示。

提示

提示和技巧以这种方式出现。

第一章:准备你的第一个 jQuery Mobile 项目

你知道 jQuery Mobile 是什么,它的历史以及它的特点和目标。现在我们实际上要构建我们的第一个 jQuery Mobile 网站(好吧,网页),看看它的使用是多么简单。

在本章中我们将:

  • 创建一个简单的 HTML 页面

  • 将 jQuery Mobile 添加到页面中

  • 利用自定义数据属性(data-*)

  • 更新 HTML 以利用 jQuery Mobile 认可的数据属性

重要的初步要点

你可以在你从 Github 下载的 ZIP 文件的 c1 文件夹中找到本章的所有源代码。如果你想手工输入所有内容,我们建议你使用类似的文件名。

构建一个 HTML 页面

让我们从一个不是移动优化的简单网页开始。明确地说,我们并不是说它不能在移动设备上使用。完全不是。但是在移动设备上可能使用起来可能不太方便。它可能很难阅读(文本太小)。它可能太宽。它可能使用在触摸屏上工作不好的表单。我们根本不知道会有什么样的问题,直到我们开始测试。(我们都在移动设备上测试过我们的网站,看看它们的工作情况,对吧?)

让我们看一看 列表 1-1:

Listing 1-1: test1.html
<html>
<head>
<title>First Mobile Example</title>
</head>
<body>
<h1>Welcome</h1>
<p>
Welcome to our first mobile web site. It's going to be the best site you've ever seen. Once we get some content. And a business plan. But the hard part is done!
</p>
<p>
<i>Copyright Megacorp &copy; 2012</i>
</p>
</body>
</html>

正如我们所说的,没有什么太复杂的,对吧?让我们在浏览器中快速看一下这个:

构建一个 HTML 页面

注意

您还可以从您在 www.packtpub.com 购买的所有 Packt 图书的帐户中下载示例代码文件。如果您在其他地方购买了这本书,您可以访问 www.packtpub.com/support 并注册,将文件直接发送到您的邮箱。

没那么糟糕,对吧?但是让我们在移动模拟器中看看同样的页面:

构建一个 HTML 页面

哇,这太小了。你可能在移动设备上以前见过这样的网页。当然,你通常可以使用捏和缩放或双击操作来增大文本的大小。但是最好立即以移动友好的视图呈现页面。这就是 jQuery Mobile 的作用所在。

获取 jQuery Mobile

在前言中,我们谈到了 jQuery Mobile 只是一组文件。这并不是为了减少创建这些文件所需的工作量,或者它们有多么强大,而是为了强调使用 jQuery Mobile 意味着您不需要安装任何特殊工具或服务器。您可以下载这些文件并简单地将它们包含在您的页面中。如果这样做对您来说太麻烦,您甚至有一个更简单的解决方案。jQuery Mobile 的文件托管在内容交付网络(CDN)上。这是他们托管的资源,并保证(尽可能保证)在线并可用。已经有多个网站在使用这些 CDN 托管的文件。这意味着当用户访问您的站点时,他们已经在他们的缓存中具有了这些资源。对于本书,我们将使用 CDN 托管的文件,但是对于这个第一个示例,我们将下载并提取这些文件。我建议无论如何都这样做,因为有时候当您在飞机上时想要迅速创建一个移动站点时。

要获取这些文件,请访问 jquerymobile.com/download。这里有几个选项,但您需要选择 ZIP 文件选项。继续下载该 ZIP 文件并解压缩它。(您之前从 Github 下载的 ZIP 文件已经包含了一份拷贝。)下面的截图演示了从 ZIP 文件中提取文件后应该看到的内容:

获取 jQuery Mobile

注意

重要说明:在撰写本书时,jQuery Mobile 正在准备发布 1.1 版本。已发布的版本是 1.0.1。但是,由于 1.1 版本即将发布,因此正在使用该版本。显然,在您阅读本书时,可能会发布更高版本。您在前面截图中看到的文件名是特定于版本的,因此请记住它们在您那里可能会有所不同。

注意 ZIP 文件包含了用于 jQuery Mobile 的 CSS 和 JavaScript 文件,以及它们的压缩版本。通常情况下,在生产应用程序中您会想要使用压缩版本,在开发过程中使用常规版本。图像文件夹包含了 6 张图像,在生成移动优化页面时由 CSS 使用。因此,明确地说,整个框架,以及本书余下部分将要讨论的所有功能,都将由 8 个文件的框架组成。当然,您还需要包含 jQuery 库。您可以在 www.jquery.com 分别下载。

实现 jQuery Mobile

好的,我们已经获取了这些文件,如何使用它们呢?要将 jQuery Mobile 支持添加到网站中,至少需要以下三个步骤:

  1. 首先在页面中添加 HTML 5 doctype:<!DOCTYPE html>。这用于帮助通知浏览器将要处理的内容类型。

  2. 添加视口元标记:<meta name="viewport" content="width=device-width, initial-scale="1">。这有助于在移动设备上查看页面时设置更好的默认值。

  3. 最后 - 必须将 CSS、JavaScript 库和 jQuery 本身包含到文件中。

让我们看看修改后的上一个 HTML 文件,添加了以上所有内容:

Listing 1-2: test2.html
<!DOCTYPE html>
<html>
<head>
<title>First Mobile Example</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href ="jquery.mobile-1.1.0-rc.1.css" />
<script type="text/javascript" src ="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="img/jquery.mobile-1.1.0- rc.1.min.js"></script>
</head>
<body>
<h1>Welcome</h1>
<p>
Welcome to our first mobile web site. It's going to be the best site you've ever seen. Once we get some content. And a business plan. But the hard part is done!
</p>
<p>
<i>Copyright Megacorp &copy; 2012</i>
</p>
</body>
</html>

大部分情况下,这个版本和listing 1完全一样,只是增加了 doctype、CSS 链接和我们的两个 JavaScript 库。请注意,我们指向了托管版本的 jQuery 库。混合本地 JavaScript 文件和远程文件是完全可以的。如果你想确保可以离线工作,你也可以简单地下载 jQuery 库。

因此,在body标签之间的代码没有变化,但是在浏览器中现在会有一个完全不同的视图。下面的截图显示了安卓手机浏览器现在如何呈现该页面:

实现 jQuery Mobile

立即看到了一些差异。最大的区别是文本的相对大小。注意它有多大,更容易阅读。正如我们所说,用户可以放大上一个版本,但许多移动用户并不知道这种技巧。这个页面立即加载,更适用于移动设备。

使用数据属性操作

正如我们在前面的例子中看到的,只需添加 jQuery Mobile 就可以大大更新我们页面以支持移动设备。但是,要真正为移动设备准备我们的页面,还涉及到更多工作。在本书的过程中,我们将使用各种数据属性来标记我们的页面,使其符合 jQuery Mobile 的要求。但是数据属性是什么?

HTML5 引入了数据属性的概念,作为向 DOM(文档对象模型)添加临时值的一种方式。例如,这是一个完全有效的 HTML:

<div id="mainDiv" data-ray="moo">Some content</div>

在上一个 HTML 中,data-ray属性是完全虚构的。但是,因为我们的属性以data-开头,所以它也是完全合法的。那么当你在浏览器中查看时会发生什么?什么也不会发生!这些数据属性的目的是与其他代码集成,比如 JavaScript,它基本上可以对它们做任何想做的事情。因此,例如,你可以编写 JavaScript 来查找 DOM 中具有data-ray属性的每个项目,并将背景颜色更改为值中指定的任何值。

这就是 jQuery Mobile 的作用,大量使用数据属性,既用于标记(创建微件)也用于行为(控制链接点击时发生的事情)。让我们看看在 jQuery Mobile 中数据属性的主要用法之一 - 定义页面、标题、内容和页脚:

Listing 1-3: test3.html
<!DOCTYPE html>
<html>
<head>
<title>First Mobile Example</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href ="jquery.mobile-1.1.0-rc.1.css" />
<script type="text/javascript" src ="http://code.jquery .com/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="img/jquery. mobile-1.1.0-rc.1.min.js"></script>
</head>
<body>
<div data-role="page">
<div data-role="header">Welcome</div>
<div data-role="content">
<p>
Welcome to our first mobile web site. It's going to be the best site you've ever seen. Once we get some content. And a business plan. But the hard part is done!
</p>
</div>
<div data-role="footer">
<i>Copyright Megacorp &copy; 2012</i>
</div>
</div>
</body>
</html>

将以前的代码片段与listing 1-2进行比较,您会发现主要的区别在于增加了div块。一个div块定义了页面。请注意,它包裹了body标签中的所有内容。在body标签内,有三个单独的div块。一个具有"header"角色,另一个具有"content"角色,最后一个标记为"footer"角色。所有块都使用data-role,这应该能给你一个线索,我们为每个块定义了一个角色。正如我们在上面所述,这些数据属性对浏览器本身并没有意义。但让我们看一下当 jQuery Mobile 遇到这些标签时会发生什么:

使用数据属性

请立即注意到,现在页眉和页脚都有黑色背景。这使它们从其他内容中更加突出。说到内容,页面文本现在与两侧之间有一些空白。一旦应用了识别的data-rolesdiv标签,所有这些都是自动完成的。这是一个主题,我们在本书中会一再看到。你将要做的绝大部分工作将涉及使用数据属性。

概要

在本章中,我们谈到了网页在移动浏览器中可能并不总是呈现良好。我们谈论了简单使用 jQuery Mobile 如何可以极大改善网站的移动体验。具体来说,我们讨论了如何下载 jQuery Mobile 并将其添加到现有的 HTML 页面,HTML 中的数据属性的含义,以及 jQuery Mobile 如何利用数据属性来增强您的页面。在下一章中,我们将在此基础上进行构建,并开始处理链接和多个内容页面。

第二章:使用 jQuery Mobile 页面

在上一章中,您看到了向简单 HTML 页面添加 jQuery Mobile 有多么容易。虽然每个网站仅由一个页面组成会很好,但实际网站由多个通过链接连接的页面组成。jQuery Mobile 使得使用多个页面变得简单,并提供了许多不同的方式来创建和链接这些页面。

在本章中,我们将:

  • 将多个页面添加到一个 jQuery Mobile 文件中

  • 讨论 jQuery Mobile 如何修改链接(以及如何禁用它)

  • 演示如何链接和添加额外文件到 jQuery Mobile 站点

  • 讨论 jQuery Mobile 如何自动处理 URL 以便于简单的书签标记

重要的初步要点

如上一章所述,本章所有代码都可通过在 Github 下载的 ZIP 文件获取。

将多个页面添加到一个文件中

在上一章中,我们处理了一个具有简单文本页面的文件。对于我们的第一个修改,我们将向文件中添加另一页并创建一个链接到它。如果你还记得,jQuery Mobile 寻找一个特定的<div>包装器来帮助它知道你的页面在哪里:<div data-role="page">。jQuery Mobile 如此简单易用的原因在于我们可以通过简单地添加另一个具有相同格式的 div 来添加另一页。以下代码段 Listing 2-1 显示了此功能的一个简单示例:

Listing 2-1: test1.html
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial- scale=1">
<title>Multi Page Example</title>
<link rel ="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src ="http://code.jquery.com/jquery- 1.7.1.min.js"></script>
<script src ="http://code.jquery.com/mobile/latest/ jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page" id="homePage">
<div data-role="header">Welcome</div>
<div data-role="content">
<p>
Welcome to our first mobile web site. It's going to be the best site you've ever seen. Once we get some content. And a business plan. But the hard part is done!
</p>
<p>
You can also <a href= "#aboutPage">learn more</a> about Megacorp.
</p>
</div>
<div data-role="footer">
<i>Copyright Megacorp &copy; 2012</i>
</div>
</div>
<div data-role="page" id="aboutPage">
<div data-role="header">About Megacorp</div>
<div data-role="content">
<p>
This text talks about Megacorp and how interesting it is. Most likely though you want to
<a href= "#homePage">return</a> to the home page.
</p>
</div>
<div data-role="footer">
<i>Copyright Megacorp &copy; 2012</i>
</div>
</div>
</body>
</html>

好的,像往常一样,我们从一些必需的内容开始:HTML5 文档类型,meta 标签,一个 CSS 包含以及两个 JavaScript 文件。这在上一章已经涵盖了,我们不会再提及它。请注意,此模板切换到了 CSS 和 JavaScript 库的 CDN 版本:

<link rel="stylesheet" href="http://code.jquery.com/ mobile/latest/jquery.mobile.min.css" />
<script src="img/jquery-1.7.1.min.js"></script>
<script src="img/ jquery.mobile.min.js"></script>

这些版本由 jQuery 团队托管,并具有始终是最新版本的好处。大多数情况下,您的访问者在到达您的移动站点之前已经加载了这些库,因此它们存在于他们的缓存中。虽然这是我们在进一步的示例中要采取的路线,但请记住,您始终可以使用您下载的版本。

现在请注意我们有两个<div>块。第一个与上一个示例没有太多变化。我们添加了一个唯一的 ID(homepage),以及一个第二段落。请注意第二段落中的链接。它使用了标准的内部链接(#aboutPage)告诉浏览器我们只想简单地将浏览器滚动到页面的那部分。指定的目标 aboutPage 在另一个 div 块中定义在下面。

在传统的网页中,这将显示为页面上的两个主要文本块。点击其中任何一个链接将简单地使浏览器上下滚动。然而,jQuery Mobile 将在这里做一些显著不同的事情。下图显示了页面在移动浏览器中的渲染方式:

将多个页面添加到一个文件中

注意到了吗?即使我们的 HTML 包含了两个文本块(两个<div>块),但它只渲染了一个。jQuery Mobile 总是显示它找到的第一个页面,并且仅显示该页面。最棒的部分来了。如果你点击链接,第二个页面将自动加载。使用你设备上的返回按钮,或者简单点击链接,将带你回到第一个页面。你还会注意到平滑的过渡效果。这是你稍后可以配置的内容。但所有这些交互,页面的显示和隐藏,过渡,都是由 jQuery Mobile 自动完成的。现在是谈论链接以及点击它们时 jQuery Mobile 所做的事情的好时机。

jQuery Mobile、链接和你

当 jQuery Mobile 遇到一个简单的链接 (<a href= "something.html"> Foo</a>) 时,它会自动捕获对该链接的任何点击,并将其更改为基于 Ajax 的加载。这意味着如果它检测到目标是页面上的某个东西,也就是说,我们上面使用的 hashmark 样式 (href="#foo") 链接,它将处理将用户过渡到新页面。如果它检测到一个指向同一服务器上另一个文件的页面,则会使用 Ajax 加载页面并替换当前可见的页面。

如果你链接到外部网站,那么 jQuery Mobile 将保持链接不变,正常的链接行为将发生。可能会有时候你想要完全禁用 jQuery Mobile 对你的链接的任何操作。在这种情况下,你可以利用一个数据属性,让框架知道它根本不应该做任何事情。一个例子:

<a href= "foo.html" data-ajax="false">Normal, non-special link</a>

正如我们在第一章中看到的准备您的第一个 jQuery 移动项目,jQuery Mobile 大量使用数据属性。它还非常擅长让你禁用你不喜欢的行为。当我们在本书中继续阅读时,你会看到一个又一个的例子,展示 jQuery Mobile 如何增强你的网站以适配移动设备。在所有这些情况下,框架都意识到可能有时你想要禁用它。

使用多个文件

在理想的世界中,我们可以用一个文件构建整个网站,永远不需要进行修订,并且每个项目都在周五下午 2 点之前完成。但在现实世界中,我们必须处理大量的文件,进行大量的修订,不幸的是,还有大量的工作。在前面的代码清单中,你看到了我们如何在一个文件中包含两个页面。jQuery Mobile 处理起来也很容易。但你可以想象,在一段时间后,这将变得难以控制。虽然我们可以包含十个、二十个、甚至三十个页面,但这将使文件变得难以处理,并且对用户的初始下载速度也会更慢。

要处理多个页面和文件,我们只需在第一个文件的同一域中制作简单的链接到其他文件。我们甚至可以将第一种技术(一个文件中的两个页面)与链接到其他文件相结合。在listing 2-2中,我们修改了第一个示例以添加到一个新页面的链接。请注意我们保留了现有的关于页面。

Listing 2-2:test2.html
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial- scale=1">
<title>Multi Page Example (2)</title>
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page" id="homePage">
<div data-role="header">Welcome</div>
<div data-role="content">
<p>
Welcome to our first mobile web site. It's going to be the best site you've ever seen. Once we get some content. And a business plan. But the hard part is done!
</p>
<p>
Find out about our wonderful
<a href= "products.html">products</a>.
</p>
<p>
You can also <a href= "#aboutPage">learn more</a> about Megacorp.
</p>
</div>
<div data-role="footer">
<i>Copyright Megacorp &copy; 2012</i>
</div>
</div>
<div data-role="page" id="aboutPage">
<div data-role="header">About Megacorp</div>
<div data-role="content">
<p>
This text talks about Megacorp and how interesting it is. Most likely though you want to
<a href= "#homePage">return</a> to the home page.
</p>
</div>
<div data-role="footer">
<i>Copyright Megacorp &copy; 2012</i>
</div>
</div>
</body>
</html>

现在,让我们看一看listing 2-3,我们的产品页面:

Listing 2-3: products.html
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial- scale=1">
<title>Products</title>
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page" id="productsPage">
<div data-role="header">Products</div>
<div data-role="content">
<p>
Our products include:
</p>
<ul>
<li>Alpha Series</li>
<li>Beta Series</li>
<li>Gamma Series</li>
</ul>
</div>
</div>
</body>
</html>

我们的产品页面相当简单,但请注意我们在顶部包含了 jQuery 和 jQuery Mobile 资源。为什么?我之前提到 jQuery Mobile 将使用 Ajax 加载其他页面。如果在 Chrome 或支持 Firebug 的 Firefox 中打开test2.html,您可以自行查看。点击产品链接将触发 XHR(类似 Ajax)请求,如下图所示:

处理多个文件

这很棒。但是当有人收藏该应用程序时会发生什么?现在让我们看看 jQuery Mobile 如何处理 URL 和导航。

提示

什么是 Firebug?

Firebug 是 Firefox 的一个扩展程序 (www.getfirebug.com),为您的浏览器提供一套开发者相关工具。Chrome 内置了类似的工具。这些工具提供了许多功能,其中之一是监视与 XHR(或 Ajax)相关的请求。

jQuery Mobile 和 URL

如果您在浏览器中打开了test2.html并进行了操作,您可能已经注意到在导航时 URL 的一些有趣之处。以下是初始 URL。(地址和文件夹当然会在您的计算机上有所不同):http://localhost/mobile/c2/test2.html

点击产品后,URL 将更改为http://localhost/mobile/c2/products.html。如果我点击返回,然后点击了解更多,我会得到http://localhost/mobile/c2/test2.html#aboutPage

在两个子页面中(产品页面和关于页面),URL 是由框架本身更改的。框架在支持的浏览器中使用history.pushStatehistory.replaceState。对于较旧的浏览器或不支持 JavaScript 操作 URL 的浏览器,将改用基于哈希的导航。 在 Internet Explorer 中查看产品链接时,如下所示:

http://localhost/mobile/c2/test2.html#/mobile/c2/products.html

有趣的是,在这种书签样式中,始终首先加载test2.html。实际上,您可以构建您的products.html只包括 div,并确保如果首先请求了产品,它仍然会正确渲染。问题出在更新、更高级的浏览器上。如果您没有包括正确的 jQuery 和 jQuery Mobile 包含文件,当他们直接访问products.html时,您将得到一个没有样式的页面。最好始终包括适当的页头文件(CSS、JavaScript 等)。任何良好的编辑器都将提供创建模板的简单方法。

额外的自定义操作

在 jQuery Mobile 中处理多个页面非常简单。您可以将前两章中讨论的内容应用到现在,构建一个相当简单但符合移动设备的网站。以下是您可能想要考虑的一些更有趣的技巧。

页面标题

在前面的示例中,当您单击Products页面时,您可能已经注意到浏览器的标题正确更新为Products。这是因为 jQuery Mobile 注意到并解析了products.html文件中的标题标签。但是,如果您单击About链接,您不会得到相同的行为。显然,由于About页面位于同一 HTML 文件中,它也具有相同的标题标签。jQuery Mobile 提供了一种简单的方法来解决这个问题,再次涉及到数据标签。以下代码片段显示了一种为嵌入页面添加标题的简单方法:

<div data-role="page" id="aboutPage" data-title="About Megacorp">
<div data-role="header">About Megacorp</div>
<div data-role="content">
<p>
This text talks about Megacorp and how interesting it is. Most likely though you want to
<a href= "#homePage">return</a> to the home page.
</p>
</div>
<div data-role="footer">
<i>Copyright Megacorp &copy; 2012</i>
</div>
</div>

注意新添加到div标签中的data-title标签。当加载About页面时,jQuery Mobile 会注意到这一点,并更新浏览器标题。同样,这仅在在一个 HTML 文件中包含多个页面时才需要。您可以在test3.html中找到这个版本:

页面标题

预取内容

将所有内容包含在一个 HTML 文件中的好处是所有页面都可以立即使用。但是负面影响(更新困难,初始下载速度慢)远远超过了这一点。大多数 jQuery Mobile 应用程序将包含多个文件,通常每个文件只包含一个或两个页面。但是,您可以确保某些页面加载更快以帮助改善用户体验。想象一下我们的Megacorp页面。它有三个页面,但是Products页面是一个单独的 HTML 文件。由于这是站点上唯一的真实内容,最有可能所有用户都会点击该链接。我们可以告诉 jQuery Mobile 在主页面加载时立即预取内容。这样,当用户单击该链接时,页面将加载得更快。再次,这归结为一个简单的数据属性。

<p>
Find out about our wonderful <a href= "products.html" data- prefetch>products</a>.
</p>

在前面的链接中,我们所做的只是在链接中添加了data-prefetch。当 jQuery Mobile 在链接中发现这一点时,它将自动立即获取内容。现在,当用户单击Products链接时,他们将更快地看到内容。这个修改已保存在test4.html中。

显然,这种技术应谨慎使用。给定一个具有四个主要链接的页面,您可能只想考虑预取两个最受欢迎的页面,而不是全部四个。

更改页面过渡方式

之前,我们提到您可以配置 jQuery Mobile 在页面之间使用的过渡效果。在本书后面,我们将讨论如何在全局范围内执行此操作,但是如果您想要在特定链接中切换到不同的过渡效果,只需在链接中包含data-transition属性即可:

<p>
Find out about our wonderful <a href= "products.html" data- transition="pop">products</a>.
</p>

许多转场还支持反向操作。通常情况下,jQuery Mobile 会判断您是否需要这样做,但如果您想强制指定一个方向,请使用 data-direction 属性:

<p>
Find out about our wonderful <a href= "products.html" data- transition="pop" data-direction="reverse">products</a>.
</p>

总结

本章进一步阐述了 jQuery Mobile 页面的概念以及如何处理多个页面。具体来说,我们看到一个物理文件可以包含许多不同的页面。jQuery Mobile 将处理除第一个页面外的所有隐藏页面。我们还看到了如何链接到其他页面以及 jQuery Mobile 如何使用 Ajax 动态加载内容到浏览器中。接下来,我们讨论了 jQuery Mobile 如何处理更新浏览器的 URL 以便启用书签功能。最后,我们讨论了两种工具,这些工具将有助于改善您的页面。第一种方法是为嵌入页面提供标题。第二种技术演示了如何预取内容以进一步改善访问您网站的用户的体验。

在下一章中,我们将看看标题、页脚和导航栏。这些将极大地增强我们的页面,并使其更易于导航。

第三章:通过标题、页脚和工具栏增强页面

工具栏提供了一种简单的方法来为移动网站添加导航元素。它们可以为用户始终可以在导航应用程序中浏览时参考的一致性或站点范围导航控件提供特别有用的功能。

在本章中,我们将:

  • 讨论如何同时创建标题和页脚

  • 讨论如何将这些标题和页脚转换为有用的工具栏

  • 演示如何创建固定定位的工具栏,无论页面的内容多大,它们都会始终显示出来

  • 展示导航栏的示例

重要的预备知识点

如前一章所述,本章的所有代码都可以通过在 Github 下载的 ZIP 文件中获得。本章中的大多数代码示例都很简短,因此在测试时应使用完整的代码。

添加标题

您之前已经使用过标题,所以代码会很熟悉。在本章中,我们将更深入地研究它们,并演示如何向您的站点标题添加其他功能,例如按钮。

如果您记得,标题可以通过简单地使用具有适当角色的 div 来定义:

<div data-role="header">My Header</div>

前一个标签将为文本添加漂亮的黑色背景,使其更加突出,如下面的截图所示:

添加标题

但是,我们可以做得更好。通过在我们的文本周围包含一个h1标签,jQuery Mobile 将使标题变得更大,并自动居中文本,如以下标签后面的截图所示:

<div data-role="header"><h1>My Header</h1></div>

添加标题

立即您就能看到差别。我们可以通过添加按钮进一步增加标题的功能。按钮可以用于导航(例如返回主屏幕),或提供到相关页面的链接。因为标题的中心用于文本,所以只有两个空格可用于左侧和右侧的按钮。您只需在标题中创建链接即可添加按钮。第一个链接将位于文本左侧,第二个链接将位于右侧。以下代码片段是一个示例:

<div data-role="header">
<a href= "index.html">Home</a>
<h1>My Header</h1>
<a href= "contact.html">Contact</a>
</div>

在移动浏览器中查看时,您将看到以下截图:

添加标题

注意,更简单的链接会自动转换为大按钮,使它们更易于使用,并对标题更具“控制”性。您可能会想,如果您只想要一个按钮,并且希望它在右侧,该怎么办?删除第一个按钮并保留第二个不起作用,如下面的代码片段所示:

<div data-role="header">
<h1>My Header</h1>
<a href= "contact.html">Contact</a>
</div>

前面的代码片段在标题中创建了一个按钮,但位于左侧。为了将按钮定位到右侧,只需添加类ui-btn-right。以下代码片段是一个示例:

<div data-role="header">
<h1>My Header</h1>
<a href= "contact.html" class="ui-btn-right">Contact</a>
</div>

您还可以指定ui-btn-left将链接放在左侧,但如前面的代码片段所示,那是正常的行为:

添加标题

图标预览

虽然不是特定的页眉工具栏功能,但 jQuery Mobile 中所有按钮都可以使用的一个有趣功能是指定一个图标。jQuery Mobile 随附了一组简单易识别的图标,并可立即使用。这些图标将在第六章中进一步讨论,创建移动优化表单,但是作为一个快速预览,以下代码片段显示了一个带有两个自定义图标的页眉:

<div data-role="header">
<a href= "index.html" data-icon="home">Home</a>
<h1>My Header</h1>
<a href= "contact.html" data-icon="info">Contact</a>
</div>

注意新属性 data-icon。在浏览器中查看时,你会看到以下截图所示内容:

图标预览

处理返回按钮

根据用户的硬件,他们可能有或者没有物理返回按钮。对于有返回按钮的设备,比如安卓手机,在 jQuery Mobile 应用中点击返回按钮会很好用。用户点击按钮后,之前所在的页面会立即加载。但是在其他设备上,比如 iPhone,没有这样的按钮可以点击。虽然你可以提供链接自己导航到其他页面,但 jQuery Mobile 提供了一些很好的内置支持,可以直接向后导航。

有两种方式可以添加自动返回按钮。 清单 3-1 显示了一个简单的、两个页面的 jQuery Mobile 网站。在第二个页面中,我们添加了一个新的数据属性 data-add-back-btn="true"。这将在第二个页面的页眉中自动创建一个返回按钮。接下来,我们还在页面内容中添加了一个简单的链接。虽然链接的实际 URL 是空白的,请注意 data-rel="back" 属性。jQuery Mobile 会检测到此链接,并自动将用户发送到上一页。以下代码片段是一个示例:

Listing 3-1: back_button_test.html
<!DOCTYPE html>
<html>
<head>
<title>Back Examples</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page">
<div data-role="header"><h1>My Header</h1></div>
<div data-role="content">
<p>
<a href= "#subpage">Go to the sub page...</a>
</p>
</div>
</div>
<div data-role="page" id="subpage" data-add-back-btn="true">
<div data-role="header"><h1>Sub Page</h1></div>
<div data-role="content">
<p>
<a href= "" data-rel="back">Go back...</a>
</p>
</div>
</div>
</body>
</html>

下面的截图展示了该功能的运行方式:

处理返回按钮

如果你好奇,按钮的文本可以通过在页面 div 中简单使用另一个数据属性来自定义:data-add-back-btn="true" data-back-btn-text="返回"。你也可以通过 JavaScript 全局地启用返回按钮支持并更改文本。这将在第九章中讨论,jQuery Mobile 中的 JavaScript 配置和实用工具

处理页脚

页脚在大部分情况下会与页眉类似。我们之前演示过使用 data-role 创建页脚:

<div data-role="footer">My Footer</div>

但是,就像我们的标题一样,如果我们在 div 标签内添加适当的 HTML,我们可以获得更好的格式:

<div data-role="header"><h4>My Footer</h4></div>

添加了 h4 标签后,我们的页脚现在居中并且稍微填充,以使它们更加突出,如以下截图所示:

处理页脚

与页眉一样,您可以在页脚中包含按钮。与页眉不同,页脚中的按钮不会自动定位到文本的左右两侧。事实上,如果您决定使用文本和按钮,您需要确保从页脚文本中删除h4标签,否则您的页脚会变得相当大。以下是一个简单的示例,其中包含两个按钮:

<div data-role="footer">
<a href= "credits.html">Credits</a>
<a href= "contact.html">Contact</a>
</div>

以下屏幕截图展示了这个变化:

操作页脚

这是有效的 - 但请注意按钮周围的空间不多。您可以通过将一个称为ui-bar的类添加到页脚div标签中来改进,如下面的代码片段所示:

<div data-role="footer" class="ui-bar">
<a href= "credits.html">Credits</a>
<a href= "contact.html">Contact</a>
</div>

操作页脚

创建固定和全屏页眉和页脚

在前面关于页眉和页脚的讨论中,您看到了一些如何添加按钮的示例。这些按钮可以用于在您的站点中导航。但是如果某个页面特别长怎么办?例如,博客条目在移动设备上查看时可能会非常长。当用户滚动时,页眉或页脚可能会离开屏幕。jQuery Mobile 提供了一种创建固定位置页眉和页脚的方法。启用此功能后,页眉和页脚将始终可见。当用户滚动时,它们可能会消失,但只要他们抬起手指并停止滚动,页眉和页脚就会重新出现。可以通过向用于页眉或页脚的 div 标签添加data-position="fixed"来启用此功能。清单 3-2展示了一个示例。为了确保页面实际上滚动,许多文本段落被重复。这已从书中的代码中删除,但存在于实际文件中。

Listing 3-2: longpage.html
<!DOCTYPE html>
<html>
<head>
<title>Fixed Positioning Example</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page">
<div data-role="header" data-position="fixed"><h1>My Header</h1></div>
<div data-role="content">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse id posuere lacus. Nulla ac sem ut eros dignissim interdum a et erat. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In ac tellus est. Nunc consequat metus lobortis enim mattis nec convallis tellus pulvinar. Nullam diam ligula, dictum sed congue nec, dapibus id ipsum. Ut facilisis pretium dui, nec varius dui iaculis ultricies. Maecenas sollicitudin urna felis, non faucibus
leo. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In id volutpat lectus.Quisque mauris ipsum, vehicula id ornare aliquet, auctor volutpat dui. Sed euismod sem in arcu dapibus condimentum dictum nibh consequat.
</p>
</div>
<div data-role="footer" data-position="fixed"><h4>My Footer</h4></div>
</div>
</body>
</html>

我们不会为这个示例提供截图,因为它不会很好地传达功能,但如果您在移动设备上尝试此操作,请注意,当您向上或向下滚动时,只要您抬起手指,页眉和页脚就会同时弹出。这使用户无论页面有多大都可以访问它们。

全屏定位

要考虑的另一种选择是所谓的全屏定位。这是一个常用于图片的比喻,但也可以用于使用固定定位页眉和页脚的情况。在这种情况下,页眉和页脚会随着点击的出现和消失而出现和消失。因此,对于照片,这允许您查看照片的原样,但也可以通过简单的点击重新获取页眉和页脚。也许,与其称之为全屏定位,不如考虑将其视为可检索的页眉和页脚。一般来说,当您希望查看页面内容时最好使用,再次,这是一个很好的例子。

要启用此功能,只需将data-fullscreen="true"添加到用于定义页面的 div 标签中即可。清单 3-3展示了此功能,如下面的代码片段所示:

Listing 3-3: fullscreen.html
<!DOCTYPE html>
<html>
<head>
<title>Full Screen Example</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page" data-fullscreen="true">
<div data-role="header" data-position="fixed"><h1>My Header</h1></div>
<div data-role="content">
<p>
<img src="img/green.png" title="Green Block">
</p>
<p>
</div>
<div data-role="footer" data-position="fixed"><h4>My Footer</h4></div>
</div>
</body>
</html>

和前一个示例一样,前面的代码片段在静态截图中展示效果不太好。在手机浏览器中打开它,看一看吧。记住,你可以点击多次来切换效果的开启和关闭。

使用导航栏

你现在已经看到了一些示例,其中包括带有页眉和页脚的按钮,但是 jQuery Mobile 还有一个更简洁的版本,称为 NavBars(或导航栏)。这些是全屏宽的条形用来放置按钮。jQuery Mobile 还支持将一个按钮标记为活动按钮。在用于导航时,这是一种标记页面为活动状态的简单方法。

NavBar 简单地说就是包含在使用data-role="navbar"的 div 标签中的无序列表。放在页脚中时,它看起来类似于以下代码片段:

<div data-role="footer">
<div data-role="navbar">
<ul>
<li><a href= "persistent_footer_index.html" class="ui-btn- active">Home</a></li>
<li><a href= "persistent_footer_credits.html" >Credits</a></li>
<li><a href= "persistent_footer_contact.html" >Contact</a></li>
</ul>
</div>
</div>

注意第一个链接使用了class="ui-btn-active"。这会将第一个按钮标记为活动状态。jQuery Mobile 不会自动为你完成这个操作,所以在构建每个页面并使用navbar时,你需要适当地移动类。以下截图显示了它的外观:

Working with navigation bars

你最多可以添加 5 个按钮,jQuery Mobile 会适当调整按钮大小以使其适应。如果超过五个,则按钮将简单地分成多行。很可能这不是你想要的。用太多的按钮来混淆用户,最终只会激怒他们。

你还可以在页眉中包括一个navbar。如果放置在文本或其他按钮之后,jQuery Mobile 将自动将其放置到下一行:

<div data-role="header">
<h1>Home</h1>
<div data-role="navbar">
<ul>
<li><a href= "persistent_footer_index.html" class="ui-btn- active">Home</a></li>
<li><a href= "persistent_footer_credits.html" >Credits</a></li>
<li><a href= "persistent_footer_contact.html" >Contact</a></li>
</ul>
</div>
</div>

Working with navigation bars

你可以在名为header_and_footer_with_navbar.html的文件中看到这两者的应用示例。

跨多个页面持久化导航栏页脚

现在让我们将前面的两个主题合并成一个令人难以置信的小功能 - 多页面持久化页脚。这需要做一些额外工作,但你可以创建一个页脚 NavBar,在切换页面时不会消失。为了做到这一点,你需要遵循一些简单的规则:

  • 你的页脚 div 必须出现在所有页面上

  • 你的页脚 div 必须在所有页面上使用相同的data-id

  • 在 NavBar 中的活动页面上,必须使用两个 CSS 类:ui-state-persistui-btn-active

  • 你还必须使用持久化页脚功能

这听起来有点复杂,但实际上在模板中只需要增加一小部分 HTML 代码。在listing 3-4中,一个虚构公司的索引页面使用了页脚 NavBar。注意当前选定页面使用了ui-state-persistui-btn-active

Listing 3-4: persistent_footer_index.html
<!DOCTYPE html>
<html>
<head>
<title>Persistent Footer Example</title>
<meta name="viewport" content="width=device-width, initial- scale=1"> <link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page">
<div data-role="header"><h1>Home</h1></div>
<div data-role="content">
<p>
This is the Home Page
</p>
</div>
<div data-role="footer" data-position="fixed" data- id="footernav">
<div data-role="navbar">
<ul>
<li><a href= "persistent_footer_index.html" class="ui-btn- active ui-state-persist">Home</a></li>
<li><a href= "persistent_footer_credits.html"> Credits</a></li>
<li><a href= "persistent_footer_contact.html"> Contact</a></li>
</ul>
</div>
</div>
</div>
</body>
</html>

下面的截图显示了页面的完整外观:

Persisting navigation bar footers across multiple pages

我们不需要太担心另外两个页面。你可以在下载的 ZIP 文件中找到它们。以下代码片段是第二个页面的页脚部分。请注意,这里唯一的变化是ui-btn-active类的移动:

<div data-role="footer" data-position="fixed" data-id="footernav">
<div data-role="navbar">
<ul>
<li><a href= "persistent_footer_index.html">Home</a></li>
<li><a href= "persistent_footer_credits.html" class="ui-btn- active ui-state-persist">Credits</a></li>
<li><a href= "persistent_footer_contact.html">Contact</a></li>
</ul>
</div>
</div>

点击从一个页面到另一个页面时,每个页面都显示平滑的过渡,但页脚栏保持不变。就像一个有框架的站点(不要抖动 - 框架并不总是被鄙视),当用户在整个站点中导航时,页脚将保持不变。

摘要

在本章中,我们讨论了如何向您的 jQuery Mobile 页面添加标题、页脚和导航栏(NavBars)。我们展示了正确的 div 标记如何在您的页面上创建格式良好的标题和页脚,以及如何使这些标题和页脚在长页面中持续存在。此外,我们演示了全屏模式用于标题和页脚。这些是点击时出现和消失的标题和页脚 - 完美用于您想在移动设备上以全屏视图显示的图像和其他项目。最后,我们看到了如何结合持久页脚和 NavBars 以创建页脚,当页面更改时不会消失。

在下一章中,我们将深入探讨列表。列表是人们为其移动站点添加导航和菜单的主要方式之一。jQuery Mobile 提供了大量选项来创建和样式化列表。

第四章:与列表一起工作

列表是为移动网站的用户提供菜单的绝佳方式。jQuery Mobile 提供了丰富的列表选项,从简单的列表到带有自定义缩略图和多个用户操作的列表。

在这一章中,我们将:

  • 谈论如何创建列表

  • 如何创建链接和子菜单样式的列表

  • 如何创建不同样式的列表

创建列表

正如您(希望!)所学到的,jQuery Mobile 在 UI 方面采取了一种增强的方法。您采用普通的、简单的 HTML,添加一些标记(有时候!),jQuery Mobile 将完成增强 UI 的繁重工作。同样的过程也适用于列表。我们之前都使用过 HTML 中的简单列表,下面的代码片段就是一个示例:

<ul>
<li>Raymond Camden</li>
<li>Scott Stroz</li>
<li>Todd Sharp</li>
<li>Dave Ferguson</li>
</ul>

我们都知道它们是如何显示的(在前一个代码片段中是一个项目符号列表)。让我们将该列表放在一个简单的 jQuery Mobile 优化页面中。Listing 4-1将一个典型页面放入我们的列表中:

Listing 4-1: test1.html
<!DOCTYPE html>
<html>
<head>
<title>Unordered List Example</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page">
<div data-role="header">
<h1>My Header</h1>
</div>
<div data-role="content">
<ul>
<li>Raymond Camden</li>
<li>Scott Stroz</li>
<li>Todd Sharp</li>
<li>Dave Ferguson</li>
</ul>
</div>
<div data-role="footer">
<h1>My Footer</h1>
</div>
</div>
</body>
</html>

给定这个 HTML,jQuery Mobile 立即为我们提供了一些好东西,如下截图所示:

创建列表

我们可以通过简单的更改来增强该列表。从listing 4-1中取出普通的<ul>标签,并添加一个data-role="listview"属性,如下代码所示:

<ul data-role="listview">

在您从 Github 下载的代码中,您可以在test2.html中找到这个修改。虽然变化很大,如下截图所示:

创建列表

您可以看到项目不再在前面有圆点符号,但它们更大,更容易阅读。当我们开始向列表中添加链接时,事情变得更加有趣。在下面的代码片段中,我为每个列表项添加了一个链接:

<ul data-role="listview">
<li><a href= "ray.html">Raymond Camden</a></li>
<li><a href= "scott.html">Scott Stroz</a></li>
<li><a href= "todd.html">Todd Sharp</a></li>
<li><a href= "dave.html">Dave Ferguson</a></li>
</ul>

再次,您可以在之前下载的 ZIP 文件中找到这个代码片段的完整文件。这个文件可以在test3.html中找到。下面的截图展示了该代码的渲染效果:

创建列表

注意新的箭头图片。当 jQuery Mobile 检测到列表中有链接时,它会自动添加。现在,您已经将一个相对简单的 HTML 无序列表转换为一个简单的菜单系统。这本身就相当令人印象深刻,但是正如我们将在本章的其余部分中看到的那样,jQuery Mobile 提供了丰富的渲染选项,让您定制列表。

您可能想知道您可以创建多复杂的菜单系统。因为 HTML 本身支持嵌套列表,jQuery Mobile 也会将它们渲染出来。Listing 4-2演示了一个嵌套列表的示例:

Listing 4-2: Nested List
<!DOCTYPE html>
<html>
<head>
<title>List Example</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page">
<div data-role="header">
<h1>My Header</h1>
</div>
<div data-role="content">
<ul data-role="listview">
<li>Games
<ul>
<li>Pong</li>
<li>Breakout</li>
<li>Tron</li>
</ul>
</li>
<li>Weapons
<ul>
<li>Nukes</li>
<li>Swords</li>
<li>Ninja Stars</li>
</ul>
</li>
<li>Planets
<ul>
<li>Earth</li>
<li>Jupiter</li>
<li>Uranus</li>
</ul>
</li>
</ul>
</div>
<div data-role="footer">
<h1>My Footer</h1>
</div>
</div>
</body>
</html>

在前面示例中使用的嵌套列表的 HTML 并没有特别之处。它是标准的。但是 jQuery Mobile 将采取内部列表并实际隐藏内容。即使在级 LI 项中没有链接,它们也会变成链接:

创建列表

单击菜单项中的一个会加载内部菜单。如果在您自己的移动设备上(或在浏览器中)运行此操作,请注意 URL 也会发生变化,它们会创建一个可书签的应用程序视图:

创建列表

使用列表功能

jQuery Mobile 提供多种不同样式的列表,以及可以应用于它们的不同功能。本章的下一部分将介绍其中的一些可用选项。这些选项没有特定的顺序,并且被呈现为您可用的选项的画廊。您可能不会(也不应该!)尝试在一个应用程序中使用所有这些选项,但是牢记 jQuery Mobile 提供的各种列表样式是件好事。

创建插入式列表

最简单、最精致的列表变化之一是将它们转换为插入式列表。这些列表不会占满设备的整个宽度。我们可以对之前用data-role="content"修改过的初始列表添加另一个属性,即data-inset="true",在以下代码块(位于test5.html中)中实现:

<ul data-role="listview" data-inset="true">
<li>Raymond Camden</li>
<li>Scott Stroz</li>
<li>Todd Sharp</li>
<li>Dave Ferguson</li>
</ul>

结果现在与之前的示例非常不同:

创建插入式列表

创建列表分隔符

您可能希望向列表中添加的另一个有趣的 UI 元素是分隔符。这是将长列表分隔成稍微容易扫描的内容的好方法。添加列表分隔符就像添加一个使用了data-role="list-divider"li标签一样简单。下面的代码片段展示了此元素的一个简单示例:

<ul data-role="listview" data-inset="true">
<li data-role="list-divider">Active</li>
<li>Raymond Camden</li>
<li>Scott Stroz</li>
<li>Todd Sharp</li>
<li data-role="list-divider">Archived</li>
<li>Dave Ferguson</li>
</ul>

在上一个代码块中,请注意两个使用了list-divider角色的新li标签。在本示例中,我将它们用于将人员列表分成两组。您可以在test6.html中找到完整的模板。以下截图显示了此内容的呈现方式:

创建列表分隔符

创建带有计数气泡的列表

jQuery Mobile 列表中的另一个有趣的 UI 技巧是计数气泡。这是一种 UI 增强,它在每个列表项的末尾添加一个简单的数字。这些数字被包裹在类似于气泡的外观中,通常用于电子邮件样式的界面。在下面的代码片段中,计数气泡用于表示在技术会议上消耗的 cookie 数量:

<ul data-role="listview" data-inset="true">
<li data-role="list-divider">Cookies Eaten</li>
<li>Raymond Camden <span class="ui-li-count">9</span></li>
<li>Scott Stroz <span class="ui-li-count">4</span></li>
<li>Todd Sharp <span class="ui-li-count">13</span></li>
<li>Dave Ferguson <span class="ui-li-count">8</span></li>
</ul>

在上一个代码片段中,我们使用了一个带有类名ui-list-countspan标签来包裹表示每个人吃的 cookie 数量的数字。一个简单的 HTML 更改,但考虑一下它如何被很好地呈现,如下面的截图所示:

创建带有计数气泡的列表

您可以在test7.html中找到此功能的完整示例。

使用缩略图和图标

列表的另一个常见需求是包含图像。jQuery Mobile 支持缩略图(较小的图像)和图标(更小的图像),它们在列表控件内显示得很好。让我们首先看一下如何在列表中包含缩略图。假设您已经有了大小适中的图像(我们的示例都是宽高都为 160 像素),您可以简单地在每个li元素中包含它们,如以下代码片段所示:

<ul data-role="listview" data-inset="true">
<li><a href="ray.html"><img src="img/ray.png"> Raymond Camden</a></li>
<li><a href="scott.html"><img src="img/scott.png"> Scott Stroz</a></li>
<li><a href="todd.html"><img src="img/todd.png"> Todd Sharp</a></li>
<li><a href="dave.html"><img src="img/dave.png"> Dave Ferguson</a></li>
</ul>

对图像没有做任何特殊处理,也没有添加任何数据属性或类。jQuery Mobile 将自动左对齐图像,并将项目文本对齐到每个li块的顶部:

使用缩略图和图标

你可以在test8.html中找到前面的演示。那么图标呢?要在代码中包含图标,请将类ui-li-icon添加到您的图像中(请注意,类的开头是ui,而不是ul。)以下代码片段是具有相同列表的示例:

<ul data-role="listview" data-inset="true">
<li><a href="ray.html"><img src="img/ray_small.png" class="ui-li-icon"> Raymond Camden</a></li>
<li><a href="scott.html"><img src="img/scott_small.png" class="ui-li- icon"> Scott Stroz</a></li>
<li><a href="todd.html"><img src="img/todd_small.png" class="ui-li- icon"> Todd Sharp</a></li>
<li><a href="dave.html"><img src="img/dave_small.png" class="ui-li- icon"> Dave Ferguson</a></li>
</ul>

使用此类时,jQuery Mobile 会缩小图像,但根据我的经验,当图像在之前被调整大小时,格式会更好。这样做还可以提高网页的速度,因为较小的图像应该会导致更快的下载时间。上面的图像都是宽高各 16 像素。结果是...

使用缩略图和图标

你可以在test9.html中找到前面的例子。

创建分割按钮列表

jQuery Mobile 列表的另一个有趣功能是 Split Button 列表。这只是一个具有多个操作的列表。当用户单击列表项时,会激活一个主要操作,并且通过列表项末尾的按钮可用于辅助操作。对于此示例,让我们首先从截图开始,然后再展示如何实现它:

创建分割按钮列表

如您所见,每个列表项在行末都有一个辅助图标。这是一个分割项目列表的示例,简单地通过向列表项添加第二个链接来定义。例如:

<ul data-role="listview" data-inset="true">
<li><a href= ray.html"><img src="img/ray_small.png" class="ui-li-icon"> Raymond Camden</a><a href="foo.html">Delete</a></li>
<li><a href= scott.html"><img src="img/scott_small.png" class="ui-li- icon"> Scott Stroz</a><a href="foo.html">Delete</a></li>
<li><a href= todd.html"><img src="img/todd_small.png" class="ui-li- icon"> Todd Sharp</a><a href="foo.html">Delete</a></li>
<li><a href= dave.html"><img src="img/dave_small.png" class="ui-li- icon"> Dave Ferguson</a><a href="foo.html">Delete</a></li>
</ul>

请注意,第二个链接的文本删除实际上被图标替换了。您可以通过将数据属性split-icon添加到您的ul标记中来指定图标,如下代码行所示:

<ul data-role="listview" data-inset="true" data-split-icon="delete">

此示例的完整代码可以在test10.html中找到。

使用搜索过滤器

对于我们最后一个列表功能,我们将查看搜索过滤器。到目前为止,我们处理的列表都相当短。但是,较长的列表可能会使用户难以找到他们要找的内容。jQuery Mobile 提供了一种非常简单的方法来向列表添加搜索过滤器。通过将data-filter="true"添加到任何列表中,jQuery Mobile 将自动在顶部添加一个搜索字段,当您输入时会进行过滤:

<ul data-role="listview" data-inset="true" data-filter="true">
<li><a href="ray.html">Raymond Camden</a></li>
<li><a href="scott.html">Scott Stroz</a></li>
<li><a href="todd.html">Todd Sharp</a></li>
<li><a href="dave.html">Dave Ferguson</a></li>
(lots of items....)
</ul>

结果看起来类似于以下截图:

使用搜索过滤器

如果您在上一个字段中开始输入,列表会在您输入时自动过滤出结果:

使用搜索过滤器

默认情况下,搜索是不区分大小写的,并且匹配列表项的任何位置。您可以在ul标签中使用data-placeholder-text="Something"来为搜索表单指定占位文本。您还可以使用data-filter-theme指定表单的特定主题。最后,您可以使用 JavaScript 根据情况添加自定义的列表过滤逻辑。

总结

本章讨论了如何在 jQuery Mobile 中使用列表视图。我们看到如何将常规 HTML 列表转换为移动优化列表,并演示了框架提供的众多列表功能类型。

在下一章中,我们将利用已学到的知识构建一个真实(尽管有点简单)的酒店移动优化网站。

第五章:实践中的一些 —— 构建一个简单的酒店移动网站

在过去的四章中,我们已经看了 jQuery Mobile 的一些特性,但我们已经有足够的知识来构建一个简单、相当基本的移动优化网站了。

在本章中,我们将:

  • 讨论我们酒店移动网站将包含什么

  • 使用 jQuery Mobile 创建酒店移动网站

  • 讨论使网站更具互动性的方法

欢迎来到 Hotel Camden

世界闻名的 Hotel Camden 现在已经有了一段时间的网络存在。(好吧,为了明确起见,我们是在编造这个!)他们是网络世界的早期创新者,从 1996 年开始建立一个简单的网站,并逐年改进他们的在线存在。现在,Hotel Camden 的在线访客可以看到房间的虚拟游览,使用令人惊叹的 3D Adobe Flash 插件查看场地,并实际上可以在线预订。不过,最近,Hotel Camden 的业主们决定他们想进入移动空间。目前,他们想要简单地开始,创建一个包含以下功能的移动优化网站:

  • 联系信息:这将包括电话号码和电子邮件地址。理想情况下,用户将能够点击这些联系方式并与真人联系。

  • 酒店位置地图:这应该包括地址,可能还有地图。

  • 可用的房间类型:这可以是一个从最简单到最华丽的房间的简单列表。

  • 最后 - 提供一种让用户进入真正网站的方式。我们接受我们的移动版本在某种程度上会有所限制(对于这个版本),所以至少我们应该提供一种让用户返回站点桌面版本的方式。

主页

让我们从 Camden Hotel 的初始主页开始。这将提供一个简单的选项列表,以及顶部的一些营销文本。这些文本实际上对任何人都没有帮助,但是营销人员不会让我们在没有它的情况下发布网站:

Listing 5-1: index.html
<!DOCTYPE html>
<html>
<head>
<title>The Camden Hotel</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page">
<div data-role="header">
<h1>Camden Hotel</h1>
</div>
<div data-role="content">
<p>
Welcome to the Camden Hotel. We are a luxury hotel specializing in catering to the rich and overly privileged. You will find our accommodations both flattering to your ego, as well as damaging to your wallet. Enjoy our complimentary wi-fi access, as well as caviar baths while sleeping in beds with gold thread.
</p>
<ul data-role="listview" data-inset="true">
<li><a href= "find.html">Find Us</a></li>
<li><a href= "rooms.html">Our Rooms</a></li>
<li><a href= "contact.html">Contact Us</a></li>
<li><a href= "">Non-Mobile Site</a></li>
</ul>
</div>
<div data-role="footer">
<h4>&copy; Camden Hotel 2012</h4>
</div>
</div>
</body>
</html>

在高层次上,listing 5-1 中的代码只是我们之前讨论过的 jQuery 页面模型的另一个实例。您可以看到包括的 CSS 和 JavaScript,以及设置页面、页眉、页脚和内容的 div 包装器。在我们的内容 div 中,您还可以看到正在使用的列表。我们留空了非移动站点选项(“非移动站点”)的 URL,因为我们没有一个真正的网站用于 Camden Hotel。

列表项的顺序也经过深思熟虑。每个项目按照员工认为的最常见请求的顺序列出,第一个是简单地找到酒店,而最后一个选项(忽略离开网站)是能够联系酒店。

总的来说 - 这个示例的想法是为我们认为酒店客户最需要的最重要的方面提供快速访问。以下截图显示了网站的外观:

主页

它并不是非常吸引人,但渲染效果很好,而且使用起来相当容易。稍后你会学习如何为 jQuery Mobile 设计主题,使您的网站不像其他所有示例一样。

寻找酒店

我们移动网站的下一页专注于帮助用户找到酒店。这将包括地址以及地图。Listing 5-2 显示了这是如何完成的:

Listing 5-2: find.html
<!DOCTYPE html>
<html>
<head>
<title>The Camden Hotel - Find Us</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/ jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page">
<div data-role="header">
<h1>Find Us</h1>
</div>
<div data-role="content">
<p>
The Camden Hotel is located in beautiful downtown Lafayette, LA. Home of the Ragin Cajuns, good food, good music, and all around good times, the Camden Hotel is smack dab in the middle of one of the most interesting cities in America!
</p>
<p>
400 Kaliste Saloom<br/>
Lafayette, LA<br/>
70508
</p>
<p>
<img src="img/ staticmap?center=400+Kaliste+Saloom,+Lafayette, LA&zoom=12&size=150x150&scale=2&maptype=roadmap& markers=label:H%7C400+Kaliste+Saloom,+Lafayette, LA&sensor=false">
</p>
</div>
<div data-role="footer">
<h4>&copy; Camden Hotel 2012</h4>
</div>
</div>
</body>
</html>

模板的开头再次包含了我们的样板,并且与以前一样,顶部有一些营销用语。但是在这之下,就是地址和地图。我们使用了谷歌的一个很酷的功能,静态地图。您可以在其主页上了解更多关于谷歌静态地图的信息:code.google.com/apis/maps/documentation/staticmaps/。基本上,这是通过 URL 参数创建静态地图的一种方式。这些地图没有缩放或平移,但如果您只想向用户展示您的业务所在的位置,这是一种非常强大且简单的方法。虽然您可以使用此 API 的大量选项,但我们的示例只是将其居中到一个地址,并在那里添加一个标记。标签 H 用于标记,但也可以使用自定义图标。以下截图显示了这是什么样子的:

寻找酒店

您可以稍微调整一下地图 URL,更改缩放比例,更改颜色等,以满足您的喜好。

列出酒店房间

现在让我们看看 rooms.html。这是我们将列出酒店可用房型的地方:

Listing 5-3: rooms.html
<!DOCTYPE html>
<html>
<head>
<title>The Camden Hotel - Our Rooms</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page">
<div data-role="header">
<h1>Our Rooms</h1>
</div>
<div data-role="content">
<p>
Select a room below to see a picture.
</p>
<ul data-role="listview" data-inset="true">
<li><a href= "room_poor.html">Simple Elegance</a></li>
<li><a href= "room_medium.html">Gold Standard</a></li>
<li><a href= "room_high.html">Emperor Suite</a></li>
</ul>
</div>
<div data-role="footer">
<h4>&copy; Camden Hotel 2012</h4>
</div>
</div>
</body>
</html>

房间页面只是他们房间的一个列表。酒店有三个级别的房间,每个都链接到列表中,用户可以获取详情。您可以在从 Github 下载的 ZIP 中找到所有三个文件,但让我们详细看看其中一个:

Listing 5-4: room_high.html
<!DOCTYPE html>
<html>
<head>
<title>The Camden Hotel - Emperor Suite</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page" data-fullscreen="true">
<div data-role="header" data-position="fixed">
<h1>Emperor Suite</h1>
</div>
<div data-role="content">
<img src="img/room2.jpg" />
</div>
<div data-role="footer" data-position="fixed">
<h4>&copy; Camden Hotel 2012</h4>
</div>
</div>
</body>
</html>

房间详细信息页面只是一个图片。不是很有用,但它可以传达重点。但请注意,我们使用了在 第三章 中学到的一个技巧,通过工具栏增强页面 - 全屏模式。这允许用户快速点击并隐藏标题,以便他们可以看到房间的全部风采:

列出酒店房间

联系酒店

现在让我们来看看联系页面。这将为用户提供到达酒店的信息:

Listing 5-5: contact.html
<!DOCTYPE html>
<html>
<head>
<title>The Camden Hotel - Contact</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page">
<div data-role="header">
<h1>Contact Us</h1>
</div>
<div data-role="content">
<p>
<b>Phone:</b> <a href= "tel:555-555-5555"> 555-555-5555</a><br/>
<b>Email:</b> <a href= "mailto:people@camdenhotel.fake"> people@camdenhotel.fake</a>
</p>
</div>
<div data-role="footer">
<h4>&copy; Camden Hotel 2012</h4>
</div>
</div>
</body>
</html>

与以前一样,我们将页面包装在正确的脚本块和 div 标签中。特别注意我们的两个链接。手机和电子邮件链接都使用可能对您不熟悉的 URL。第一个 tel:555-555-555 实际上是请求移动设备拨打电话号码的一种方式。点击它会弹出拨号器,如下图所示:

联系酒店

这使得用户可以快速拨打酒店电话。同样,mailto 链接可以让用户快速给酒店发送电子邮件。还有其他的 URL 方案,包括用于发送短信的方案。正如你可能猜到的那样,这个方案使用形式“sms”,所以要开始向电话号码发送短信,你可以使用以下 URL:sms://5551112222

摘要

在本章中,我们总结了到目前为止所学的知识,并为一家虚拟酒店建立了一个非常简单但有效的网站。这个网站分享了关于酒店的基本信息,方便需要在移动设备上了解酒店情况的人,利用了 Google 的静态地图 API 来创建一个显示酒店位置的简单地图,并演示了使用telmailtoURL 方案进行自动拨打电话和发送电子邮件的方法。

在下一章中,我们将看看表单以及如何使用 jQuery Mobile 自动改进它们。

第六章:使用表单和 jQuery Mobile

在本章中,我们将研究表单。表单是大多数网站的关键部分,因为它们为用户提供了与网站交互的主要方式。jQuery Mobile 在使表单既可用又为移动设备设计上有很大帮助。

在本章中,我们将:

  • 讨论 jQuery Mobile 处理表单的方式

  • 使用示例表单并描述结果的处理方式

  • 讨论如何构建特定类型的表单并利用 jQuery Mobile 的惯例

在您开始之前

在本章中,我们将讨论表单以及 jQuery Mobile 如何增强它们。作为我们讨论的一部分,我们将把我们的表单提交到服务器上。为了让服务器实际对响应做些什么,我们将使用 Adobe 的一个称为 ColdFusion 的应用服务器。ColdFusion 在生产中不免费,但是在开发中是 100%免费的,并且是构建 Web 应用程序的一个很好的服务器。您不需要下载 ColdFusion。如果不这样做,您在本章中使用的表单不应该提交。本章确实讨论了如何提交表单,但是对表单的响应并不是真正关键的。如果您了解另一种语言,比如 PHP,您应该能够简单地模仿 ColdFusion 使用的代码来回显表单数据。

ColdFusion(当前版本为 9)可在www.adobe.com/go/coldfusion下载。Windows、OS X 和 Linux 版本都存在。如上所述,您可以在开发服务器上免费运行 ColdFusion,没有超时限制。

jQuery Mobile 对表单的处理

在我们进入代码之前,有两件非常重要的事情您应该知道 jQuery Mobile 将如何处理您的 HTML 表单:

  • 所有表单都将通过 Ajax 提交其数据。这意味着数据直接发送到您表单的操作,并且结果将被带回给用户并放置在容纳表单的页面中。这样可以防止完整页面重新加载。

  • 所有表单字段都会自动增强,每个都有自己的方式。随着我们在本章中的进行,您将看到这方面的示例,但基本上 jQuery Mobile 修改您的表单字段以在移动设备上更好地工作。一个很好的例子是按钮。jQuery Mobile 自动扩大和增高按钮,使其更易于在手机的小型形式因素中点击。如果出于某种原因您不喜欢这样做,jQuery Mobile 提供了一种方法来禁用此功能,可以在全局或每次使用的基础上。

考虑到这一点,让我们看看我们第一个示例列表 6-1:

Listing 6-1: test1.html
<!DOCTYPE html>
<html>
<head>
<title>Form Example 1</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page">
<div data-role="header">
<h1>Form Demo</h1>
</div>
<div data-role="content">
<form action="echo.cfm" method="post">
<div data-role="fieldcontain">
<label for="name">Name:</label>
<input type="text" name="name" id="name" value="" />
</div>
<div data-role="fieldcontain">
<label for="email">Email:</label>
<input type="text" name="email" id="email" value="" />
</div>
<div data-role="fieldcontain">
<input type="submit" name="submit" value="Send" />
</div>
</form>
</div>
</div>
</body>
</html>

与往常一样,模板从适当的包含开始,并使用特殊标记的div标签包裹页面的主要内容。我们将专注于主要内容区域的表单字段。建议每个表单字段都用以下标记包装:

<div data-role="fieldcontain">
</div>

这将帮助 jQuery Mobile 对齐标签和表单字段。一会儿你就会明白原因。我们的表单有两个文本字段,一个用于姓名,一个用于电子邮件。最后一项只是提交按钮。所以除了使用fieldcontain包装器并确保我们的表单字段有标签之外,这里没有发生任何特别的事情。不过马上你就会看到表单发生了一些相当令人印象深刻的变化:

jQuery Mobile 对表单的处理

请注意标签是如何显示在表单字段上方的。这在移动设备上为字段提供了更多的空间。同时请注意提交按钮很大且易于点击。如果我们旋转设备,jQuery Mobile 会更新显示以利用额外的空间:

jQuery Mobile 对表单的处理

请注意,字段现在直接对齐到其标签的右侧。那么当表单提交时会发生什么?正如本章开头所提到的,我们将使用 ColdFusion 来处理对表单请求的响应。我们的echo.cfm模板将简单地循环遍历所有表单字段并将它们显示给用户:

Listing 6-2: echo.cfm
<div data-role="page">
<div data-role="header">
<h1>Form Result</h1>
</div>
<div data-role="content">
<cfloop item="field" collection="#form#">
<cfoutput>
<p>
The form field #field# has the value #form[field]#.
</p>
</cfoutput>
</cfloop>
</div>
</div>

如果您不想安装 ColdFusion,您可以简单地编辑listing 6-1中的表单操作值,将其指向一个 PHP 文件,或者任何其他服务器端处理器。您也可以将其简单地更改为文件本身test1.html。当您提交时,什么都不会发生,但您也不会收到错误。这是设备在提交后显示的内容:

jQuery Mobile 对表单的处理

jQuery Mobile 更新表单字段的另一个很好的例子是textarea。textarea,默认情况下,在移动设备上使用起来可能会非常困难,特别是当文本量超出textarea的大小并添加滚动条时。在以下代码清单中,我们只是修改了先前的表单,包括第三个项目,一个使用了textarea的个人简介字段。完整文件可在本书的代码 ZIP 文件中找到。以下代码片段是添加到前两个字段之后的div块:

<div data-role="fieldcontain">
<label for="bio">Bio:</label>
<textarea name="bio" id="bio" />
</div>

当在设备上查看时,textarea会展开以吸收更多的宽度,就像常规文本字段一样,并且会变得更高:

jQuery Mobile 对表单的处理

但一旦您开始输入并输入多行文本时,textarea会自动扩展:

jQuery Mobile 对表单的处理

这样比使用滚动条更容易阅读。现在让我们看看另一个常见的表单选项——单选按钮和复选框。

操作单选按钮和复选框

单选按钮和复选框也被更新为在移动设备上很好地工作,但需要稍微多一点的代码。在之前的例子中,我们用一个div标签包装了表单字段,该标签使用了data-role="fieldcontain"。当操作单选按钮和复选框时,需要一个额外的标签:

<fieldset data-role="controlgroup">

fieldset标签将用于将您的单选按钮或复选框分组在一起。清单 6-3演示了一组单选按钮和一组复选框:

Listing 6-3: test3.html
<!DOCTYPE html>
<html>
<head>
<title>Form Example 3</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page">
<div data-role="header">
<h1>Form Demo</h1>
</div>
<div data-role="content">
<form action="echo.cfm" method="post">
<div data-role="fieldcontain">
<fieldset data-role="controlgroup">
<legend>Favorite Movie:</legend>
<input type="radio" name="favoritemovie" id="favoritemovie1" value="Star Wars">
<label for="favoritemovie1">Star Wars</label>
<input type="radio" name="favoritemovie" id="favoritemovie2" value="Vanilla Sky">
<label for="favoritemovie2">Vanilla Sky</label>
<input type="radio" name="favoritemovie" id="favoritemovie3" value="Inception">
<label for="favoritemovie3">Inception</label>
</fieldset>
</div>
<div data-role="fieldcontain">
<fieldset data-role="controlgroup">
<legend>Favorite Colors:</legend>
<input type="checkbox" name="favoritecolor" id="favoritecolor1" value="Green">
<label for="favoritecolor1">Green</label>
<input type="checkbox" name="favoritecolor" id="favoritecolor2" value="Red">
<label for="favoritecolor2">Red</label>
<input type="checkbox" name="favoritecolor" id="favoritecolor3" value="Yellow">
<label for="favoritecolor3">Yellow</label>
</fieldset>
</div>
<input type="submit" name="submit" value="Send" />
</div>
</form>
</div>
</div>
</body>
</html>

我们的表单有两个主要问题——您最喜欢的电影是什么以及您最喜欢的颜色是什么?每个块都包裹在我们之前提到的div标签中。在其中是使用data-role="controlgroup"fieldset。最后,您然后有您的单选按钮和复选框组。重要的是要在适当的标签标签内包含标签,就像之前的每个示例中一样。一旦渲染,jQuery Mobile 将这些组合成一个漂亮的、单一的控件:

使用单选按钮和复选框

注意每个项目的宽可点击区域。这样在移动设备上更容易选择项目。这两个控件的另一个有趣功能是将它们转换为水平按钮栏的能力。在test4.html中,两个fieldset标签被修改以包含一个新的数据属性:

<fieldset data-role="controlgroup" data-type="horizontal">

使用单选按钮和复选框

正如您所见,效果在第一组中的较长文本中效果不佳,因此请务必进行测试。

使用选择菜单

另一个 jQuery Mobile 表单增强的示例是使用选择菜单。与我们之前的示例一样,我们利用一个fieldcontain divlabel标签,但在那之外,select标签像往常一样使用。以下代码片段来自test5.html

<div data-role="fieldcontain">
<label for="favmovie">Favorite Movie:</label>
<select name="favmovie" id="favmovie">
<option value="Star Wars">Star Wars</option>
<option value="Revenge of the Sith">Revenge of the Sith</option>
<option value="Tron">Tron</option>
<option value="Tron Legacy">Tron Legacy</option>
</select>
</div>

在移动设备上,选择的初始显示被修改为更容易点击:

使用选择菜单

但是,一旦点击,设备的原生菜单将接管。在您使用的平台上,这将看起来不同。以下截图显示了 Android 如何渲染菜单:

使用选择菜单

另一个与选择字段一起使用的选项是分组。jQuery Mobile 允许您垂直或水平将多个选择字段组合在一起。在这两种情况下,唯一需要的就是将您的选择字段包装在一个fieldset中,并使用data-rolecontrolgroup,就像我们之前为单选按钮和复选框所做的那样。以下代码片段是垂直对齐的选择字段组的示例:

<div data-role="fieldcontain">
<fieldset data-role="controlgroup">
<legend>Trip Setup:</legend>
<label for="location">Location</label>
<select name="location" id="location">
<option value="Home">Home</option>
<option value="Work">Work</option>
<option value="Moon">Moon</option>
<option value="Airport">Airport</option>
</select>
<label for="time">Time</label>
<select name="time" id="time">
<option value="Morning">Morning</option>
<option value="Afternoon">Afternoon</option>
<option value="Evening">Evening</option>
</select>
<label for="time">Meal</label>
<select name="meal" id="meal">
<option value="Meat">Meat</option>
<option value="Vegan">Vegan</option>
<option value="Kosher">Kosher</option>
</select>
</fieldset>
</div>

此模板的其余部分可以在test6.html中找到。以下截图显示了它的外观:

使用选择菜单

请注意 jQuery Mobile 如何将它们分组在一起,并将边角圆润地呈现出来。水平版本可以通过在 fieldset 标签中添加一个data-type="horizontal"属性来实现。另外,重要的是要删除使用“fieldcontain”的div。这是一个示例(完整文件可以在test7.html中找到):

<div data-role="page">
<div data-role="header">
<h1>Form Demo</h1>
</div>
<div data-role="content">
<form action="echo.cfm" method="post">
<fieldset data-role="controlgroup" data-type="horizontal">
<legend>Trip Setup:</legend>
<label for="location">Location</label>
<select name="location" id="location">
<option value="Home">Home</option>
<option value="Work">Work</option>
<option value="Moon">Moon</option>
<option value="Airport">Airport</option>
</select>
<label for="time">Time</label>
<select name="time" id="time">
<option value="Morning">Morning</option>
<option value="Afternoon">Afternoon</option>
<option value="Evening">Evening</option>
</select>
<label for="meal">Meal</label>
<select name="meal" id="meal">
<option value="Meat">Meat</option>
<option value="Vegan">Vegan</option>
<option value="Kosher">Kosher</option>
</select>
</fieldset>
<div data-role="fieldcontain">
<input type="submit" name="submit" value="Send" />
</div>
</form>
</div>
</div>

以下截图显示了结果:

使用选择菜单

搜索、切换和滑块字段

除了接受常规表单字段并使其更好地工作外,jQuery Mobile 还有助于使一些较新的 HTML5 表单字段在多个浏览器上正确工作。尽管在桌面上对于每个主要浏览器的支持尚未确定,但 jQuery Mobile 为搜索、切换和滑块字段提供了内置支持。让我们看看每个字段。

搜索字段

这三个新字段中最简单的是搜索字段,它在您开始输入后在字段末尾添加了一个快速删除图标。某些设备还会在前面放置一个沙漏图标,以帮助传达该字段用于某种类型的搜索的概念。要使用此字段,只需将类型从文本切换到搜索即可。就像下面的来自test8.html的例子一样:

<div data-role="fieldcontain">
<label for="name">Name:</label>
<input type="search" name="name" id="name" value="" />
</div>

以下截图是结果。请注意,我已经输入了一些内容,字段会自动在末尾添加一个删除图标:

搜索字段

翻转切换字段

翻转切换字段是在一个值和两个值之间切换的控件。创建切换字段涉及使用具有特定 data-role 值的选择控件。现在,这里可能会有点混乱。要使选择字段变为切换字段,您可以使用data-role="slider"。稍后我们将看到另一个滑块控件,但它使用了不同的技术。只需记住,即使您在 HTML 中看到"slider",我们实际上正在创建的是一个切换控件。让我们看一个简单的例子。(您可以在test9.html中找到此完整源代码):

<div data-role="fieldcontain">
<label for="gender">Gender:</label>
<select name="gender" id="gender" data-role="slider">
<option value="0">Male</option>
<option value="1">Female</option>
</select>
</div>

一旦由 jQuery Mobile 渲染,以下截图显示了结果,首先是默认的男性选项,然后是女性

翻转切换字段翻转切换字段

滑块字段

对于我们特殊字段中的最后一个,我们来看看滑块。与搜索字段一样,这是基于一项 HTML5 规范,在某些浏览器中有效,在其他浏览器中无效。jQuery Mobile 只需使其在所有地方都起作用。为了启用此字段,我们将普通文本字段切换类型为"range",为我们的滑块提供范围,我们还提供了minmax值。您还可以通过添加属性data-highlight="true"为滑块添加额外的颜色。以下代码片段是一个示例。(您可以在test10.html中找到完整文件):

<div data-role="fieldcontain">
<label for="coolness">Coolness:</label>
<input type="range" name="coolness" id="coolness" min="0" max="100" value="22" data-highlight="true">
</div>

结果是一个滑块控件和一个输入字段。两者都允许您在最小值和最大值之间修改值:

滑块字段

请注意,范围的 HTML5 规范支持步长属性。虽然这在一些浏览器中有效,但 jQuery Mobile 尚未直接支持。换句话说,jQuery Mobile 不会尝试在没有内置支持的浏览器上添加此支持。只要您意识到它可能不始终按预期工作,就可以添加该属性。

使用原生表单控件

现在你已经看到 jQuery Mobile 为增强和加强你的表单字段以在移动设备上更好地工作所做的努力,但如果你不喜欢 jQuery Mobile 的工作呢?如果你喜欢它对按钮的更新但厌恶它对下拉框的更改呢?幸运的是,jQuery Mobile 提供了一种简单的方法来禁用自动增强。在每个你希望保持不变的字段中,只需在标记中添加 data-role="none"。所以根据以下 HTML,第一个项目将被更新,而第二个项目不会:

<input type="submit" value="Awesome">
<input type="submit" value="Not So Awesome" data-role="none">

使用原生表单控件

另一个选项是在初始化 jQuery Mobile 时禁用它。该选项将在第九章中讨论,jQuery Mobile 中的 JavaScript 配置和实用程序

使用“迷你”字段

在前面的示例中,我们看到了 jQuery Mobile 如何自动增强表单字段,使它们在较小的、基于触摸的设备上更易于使用。一般来说,jQuery Mobile 将你的字段变得更大更漂亮。虽然这在大多数情况下是可取的,但你可能希望让你的表单字段减肥一点。这对于将表单字段放置在页眉或页脚中尤其如此。jQuery Mobile 支持任何表单字段上的属性,可以创建字段的更小版本:data-mini="true"。以下代码片段是一个完整的示例:

<div data-role="fieldcontain">
<label for="name">Name:</label>
<input type="search" name="name" id="name" value="" />
</div>
<div data-role="fieldcontain">
<label for="name">Name (Slim):</label>
<input type="search" name="name" id="name" value="" data- mini="true" />
</div>

结果有点微妙,但你可以在以下截图的第二个字段中看到高度差异:

使用“迷你”字段

这个例子可以在名为 test12.html 的文件中找到。

摘要

在本章中,我们讨论了表单以及它们在 jQuery Mobile 应用程序中的呈现方式。我们讨论了 jQuery Mobile 如何自动将所有表单提交转换为基于 Ajax 的调用,并更新表单字段以在移动设备上更好地工作。不仅所有的表单字段都会自动更新,而且你还可以使用新的控件,如切换、滑块和搜索输入。

在下一章中,我们将看一下模态对话框、小部件和布局网格。这些为你的移动优化站点提供了额外的 UI 选项。

第七章:创建模态对话框、网格和可折叠块

在这一章中,我们将看到对话框、网格和可折叠块。在之前的章节中,我们已经处理过页面、按钮和表单控件。虽然 jQuery Mobile 为它们提供了很好的支持,但在框架中还有更多的 UI 控件可供使用。

在本章中,我们将:

  • 讨论如何链接到和创建对话框以及如何处理离开它们

  • 演示网格及如何将其添加到你的页面

  • 展示可折叠块如何让你在很小的空间内装入大量信息

创建对话框

对话框:至少在 jQuery Mobile 框架下:是覆盖现有页面的小窗口。通常为用户提供短消息或问题。它们通常还包括一个按钮,允许用户关闭对话框并返回网站。在 jQuery Mobile 中创建对话框只需要简单地为链接添加一个属性:data-rel="dialog"。下面的示例演示了一个样例:

Listing 7-1: test1.html
<!DOCTYPE html>
<html>
<head>
<title>Dialog Test</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/ jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page" id="first">
<div data-role="header">
<h1>Dialog Test</h1>
</div>
<div data-role="content">
<p>
<a href="#page2">Another Page (normal)</a>
</p>
<p>
<a href="#page3" data-rel="dialog">A Dialog (dialog)</a>
</p>
</div>
</div>
<div data-role="page" id="page2">
<div data-role="header">
<h1>The Second</h1>
</div>
<div data-role="content">
<p>
This is the Second
</p>
</div>
</div>
<div data-role="page" id="page3">
<div data-role="header">
<h1>The Third</h1>
</div>
<div data-role="content">
<p>
This is the Third
</p>
</div>
</div>
</body>
</html>

这是一个简单的多页面 jQuery Mobile 站点。请注意我们如何链接到第二和第三页。第一个链接很典型。然而,第二个链接包括了前面提到的data-rel属性。请注意第二和第三页都是以通常方式定义的。所以我们在此处的唯一改变是在链接上。当点击第二个链接时,页面将完全不同地呈现:

创建对话框

记住,该页面并未有不同的定义。你在上一屏幕截图中看到的变化是由链接本身的更改驱动的。就是这样!点击小的X按钮将隐藏对话框并将用户带回原始页面。

该页面内的任意链接也将处理关闭对话框。如果你希望添加一个类似取消的按钮或链接,可以在链接中使用data-rel="back"。链接的目标应为启动对话框的页面。列表 7-2展示了之前模板的修改版本。在这个版本中,我们只是在对话框中添加了两个按钮。第一个按钮将打开第二页,而第二个将作为一个取消操作。

Listing 7-2: test2.html
<!DOCTYPE html>
<html>
<head>
<title>Dialog Test (2)</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page" id="first">
<div data-role="header">
<h1>Dialog Test</h1>
</div>
<div data-role="content">
<p>
<a href="#page2">Another Page (normal)</a>
</p>
<p>
<a href="#page3" data-rel="dialog">A Dialog (dialog)</a>
</p>
</div>
</div>
<div data-role="page" id="page2">
<div data-role="header">
<h1>The Second</h1>
</div>
<div data-role="content">
<p>
This is the Second
</p>
</div>
</div>
<div data-role="page" id="page3">
<div data-role="header">
<h1>The Third</h1>
</div>
<div data-role="content">
<p>
This is the Third
</p>
<a href="#page2" data-role="button">Page 2</a>
<a href="#first" data-role="button" data- rel="back">Cancel</a>
</div>
</div>
</body>
</html>

这个模板中的主要变化是对话框中按钮的添加,包含在page3 div中。请注意第一个链接被设置为按钮,但在外面却是一个简单的链接。第二个按钮包含了添加的data-rel="back"属性。这将简单地关闭对话框。下面的截图展示了添加按钮后对话框的样子:

创建对话框

使用网格布局内容

网格是 jQuery Mobile 中少数不使用特定数据属性的特性之一。相反,你只需为内容指定 CSS 类即可使用网格布局。

网格有四种类型:两列、三列、四列和五列。(你可能不会想在手机设备上使用五列。最好是留给平板。)

你可以通过使用 ui-grid-X 类开始一个网格,其中 X 可以是 a, b, c, 或 dui-grid-a 表示两列网格,ui-grid-b 是三列网格。你大概能猜到 cd 代表什么。

所以要开始一个两列网格,你需要用以下代码包裹你的内容:

<div class="ui-grid-a">
Content
</div>

div 标签内,你可以为内容的每个 "单元格" 使用一个 div。网格调用的类以 ui-block-X 开头,Xadui-block-a 会被用于第一个单元格,ui-block-b 用于下一个,以此类推。这与 HTML 表格非常相似。

综合起来,下面的代码片段展示了一个简单的两列网格,其中有两个单元格的内容:

<div class="ui-grid-a">
<div class="ui-block-a">Left</div>
<div class="ui-block-b">Right</div>
</div>

单元格内的文本会自动换行。7-3 展示了一个简单的网格,其中一个单元格中有大量文本:

Listing 7-3: test3.html
<!DOCTYPE html>
<html>
<head>
<title>Grid Test</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page" id="first">
<div data-role="header">
<h1>Grid Test</h1>
</div>
<div data-role="content">
<div class="ui-grid-a">
<div class="ui-block-a">
<p>
This is my left hand content. There won't be a lot of it.
</p>
</div>
<div class="ui-block-b">
<p>
This is my right hand content. I'm going to fill it with some dummy text.
</p>
<p>
Bacon ipsum dolor sit amet andouille capicola spare ribs, short loin venison sausage prosciutto turducken turkey flank frankfurter pork belly short ribs. Venison frankfurter filet mignon, jowl meatball hamburger pastrami pork chop drumstick. Fatback pancetta boudin, ribeye shoulder capicola cow leberkäse bresaola spare ribs prosciutto venison ball tip jowl andouille. Beef ribs t-bone swine, tail capicola turkey pork belly leberkäse frankfurter jowl. Shankle ball tip sirloin frankfurter bacon beef ribs. Tenderloin beef ribs pork chop, pancetta turkey bacon short ribs ham flank chuck pork belly. Tongue strip steak short ribs tail swine.
</p>
</div>
</div>
</div>
</div>
</body>
</html>

在移动浏览器中,你可以清楚地看到两列:

使用网格布局内容

然后就是简单地切换到其他类来处理其他类型的网格。例如,设置一个四列网格类似于以下代码片段:

<div class="ui-grid-c">
<div class="ui-block-a">1st cell</div>
<div class="ui-block-b">2nd cell</div>
<div class="ui-block-c">3rd cell</div>
</div>

同样,记住你的目标受众。任何超过两列的都可能在手机上显得太窄。

要在网格中创建多行,只需重复块。下面的代码片段展示了一个有两行单元格的网格的简单示例:

<div class="ui-grid-a">
<div class="ui-block-a">Left Top</div>
<div class="ui-block-b">Right Top</div>
<div class="ui-block-a">Left Bottom</div>
<div class="ui-block-b">Right Bottom</div>
</div>

请注意,这里没有行的概念。 jQuery Mobile 可以处理当块重新以标记为 ui-block-a 开始时,它应该创建一个新的行。下面的代码片段,7-4 是一个简单的例子:

Listing 7-4:test4.html
<!DOCTYPE html>
<html>
<head>
<title>Grid Test (2)</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/ jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page" id="first">
<div data-role="header">
<h1>Grid Test</h1>
</div>
<div data-role="content">
<div class="ui-grid-a">
<div class="ui-block-a">
<p>
<img src="img/ray.png">
</p>
</div>
<div class="ui-block-b">
<p>
This is Raymond Camden. Here is some text about him. It may wrap or it may not but jQuery Mobile will make it look good. Unlike Ray!
</p>
</div>
<div class="ui-block-a">
<p>
This is Scott Stroz. Scott Stroz is a guy who plays golf and is really good at FPS video games.
</p>
</div>
<div class="ui-block-b">
<p>
<img src="img/scott.png">
</p>
</div>
</div>
</div>
</div>
</body>
</html>

下面的截图显示了结果:

使用网格布局内容

使用可折叠内容

在本章中,我们要看的最后一个小部件支持可折叠内容。这只是可以折叠和展开的内容。创建一个可折叠内容小部件就像简单地用 div 包裹它,加上 data-role="collapsible",并包含内容的标题。考虑以下简单的例子:

<div data-role="collapsible">
<h1>My News</h1>
<p>This is the latest news about me...
</div>

渲染时,jQuery Mobile 会将标题转换为可展开和折叠内容的可点击横幅。让我们看一个真实的例子。想象一下,你想要分享公司主要地址的位置。你还想要包括分公司。由于大多数人不会关心其他办公室,我们可以使用一个简单的可折叠内容小部件来默认隐藏内容。下面的代码片段,7-5 展示了一个例子:

Listing 7-5: test5.html
<!DOCTYPE html>
<html>
<head>
<title>Collapsible Content</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/ jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page" id="first">
<div data-role="header">
<h1>Our Offices</h1>
</div>
<div data-role="content">
<p>
<strong>Main Office:</strong><br/>
400 Elm Street<br/>
New York, NY<br/>
90210
</p>
<div data-role="collapsible">
<h3>Satellite Offices</h3>
<p>
<strong>Asia:</strong>
Another Address Here
</p>
<p>
<strong>Europe:</strong>
Another Address Here
</p>
<p>
<strong>Mars:</strong>
Another Address Here
</p>
</div>
</div>
</div>
</body>
</html>

你可以看到其他办公室都被使用新的可折叠内容角色的 div 标签包裹着。查看时,请注意它们是隐藏的:

使用可折叠内容

点击标题旁边的 + 将其打开,再次点击将其重新关闭:

处理可折叠内容

默认情况下,jQuery Mobile 会折叠和隐藏内容。当然,您也可以告诉 jQuery Mobile 初始化块时打开而不是关闭。要这样做,只需在初始的div标签中添加data-collapsed="false"。例如:

<div data-role="collapsible" data-collapsed="false">
<h1>My News</h1>
<p>This is the latest news about me...
</div>

这个区域仍然具有折叠和打开的能力,但默认情况下会打开。

可折叠内容块的另一个选项是对折叠区域的内容进行主题化。通过提供data-content-theme属性,您可以指定一个背景颜色,使区域更具连贯性。主题化在第十一章中有介绍,主题化 jQuery Mobile,但我们可以看一个快速示例。在以下截图中,第一个区域没有使用该功能,而第二个区域使用了:

处理可折叠内容

注意到图标也向右移动了。这展示了另一个选项,data-iconpos。在code文件夹中的test5-2.html中找到的以下代码片段演示了这些选项:

<div data-role="collapsible">
<h3>First</h3>
<p>
Hello World...
</p>
</div>
<div data-role="collapsible" data-content-theme="c" data- iconpos="right">
<h3>First</h3>
<p>
Hello World again...
</p>
</div>

最后,您可以将多个可折叠区域合并成一个称为手风琴的单元。只需将多个可折叠块放入一个新的div标签中即可完成此操作。这个div标签使用data-role="collapsible-set"将内部块作为一个单位。清单 7-6演示了一个示例。它采用了早期的办公地址示例,并为每个唯一的地址使用了一个可折叠集:

Listing 7-6: test6.html
<!DOCTYPE html>
<html>
<head>
<title>Collapsible Content</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page" id="first">
<div data-role="header">
<h1>Our Offices</h1>
</div>
<div data-role="content">
<div data-role="collapsible-set">
<div data-role="collapsible">
<h3>Main Office</h3>
<p>
400 Elm Street<br/>
New York, NY<br/>
90210
</p>
</div>
<div data-role="collapsible">
<h3>Asia</h3>
<p>
Another Address Here
</p>
</div>
<div data-role="collapsible">
<h3>Europe</h3>
<p>
Another Address Here
</p>
</div>
<div data-role="collapsible">
<h3>Mars</h3>
<p>
Another Address Here
</p>
</div>
</div>
</div>
</div>
</body>
</html>

清单 7-6中,我们只需使用一个可折叠集的div标签包装四个可折叠块。完成后,jQuery Mobile 将它们分组在一起,并在打开另一个时自动关闭一个:

处理可折叠内容

概要

在本章中,我们更多地了解了 jQuery Mobile 如何增强基本的 HTML,以为我们的移动页面提供额外的布局控件。通过对话框,我们学会了向用户提供基本、快速、模态消息的方法。通过网格,我们学到了一种新的方法来轻松地将内容布局在列中。最后,通过可折叠的内容块,我们学到了一种很酷的方式来分享额外的内容,而不占用太多的屏幕空间。

在下一章中,我们将演示一个完整的、真实的示例,创建一个基本的笔记跟踪器。它利用了额外的 HTML5 功能,以及你在过去几章中学到的一些 UI 技巧。

第八章:jQuery Mobile 配置、实用工具和 JavaScript 方法

在本章中,我们将看看如何使用 JavaScript 进一步配置和增强 jQuery Mobile 网站。到目前为止,我们已经使用 HTML 和 CSS 来生成所有内容。现在我们将看看额外的脚本,为您的网站添加额外的功能。

在本章中,我们将:

  • 解释了如何通过 JavaScript 配置 jQuery Mobile 网站

  • 讨论了使用 jQuery Mobile 的各种 JavaScript 实用工具以及它们的使用方式

  • 解释了用于处理增强的 jQuery Mobile 表单和小部件控件的 API

配置 jQuery Mobile

jQuery Mobile 对您做了许多事情 - 从改善页面导航到改变表单控件的工作方式。所有这些都是为了让您的内容在移动环境中更好地运行。然而,有时您并不希望 jQuery Mobile 做某些事情,或者也许您只是想微调框架的行为。这就是配置的作用所在。

要配置 jQuery Mobile 网站,您首先需要编写代码来监听mobileinit事件。这可以使用普通的 jQuery 事件处理程序来监听,类似以下代码片段:

$(document).bind("mobileinit", function() {
//your customization here
});

为了捕获此事件,您必须在 jQuery Mobile 实际加载之前对其进行配置。最简单的方法,也是 jQuery Mobile 文档建议的方法,就是将此代码放在加载 jQuery Mobile JavaScript 库之前的脚本中。以下代码片段显示了我们文件标头的典型样式:

<!DOCTYPE html>
<html>
<head>
<title>Dialog Test</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>

请注意,jQuery Mobile 库是最后一个加载的。我们可以简单地在其之前添加一个新的脚本标签:

<!DOCTYPE html>
<html>
<head>
<title>Dialog Test</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/config.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>

配置 jQuery Mobile 就像更新$.mobile对象一样简单。以下代码片段是一个简单的示例:

$(document).bind("mobileinit", function() {
$.mobile.someSetting="some value here";
});

此对象包含一组可配置的各种设置的键/值对。实际上不需要创建它 - 它在运行事件处理程序时已经存在。另一个选项是利用 jQuery 的extend()功能,如下面的代码片段所示:

$(document).bind("mobileinit", function() {
$.extend($.mobile, {
someSetting:"some value here"
});
});

两种表单都可以,并且完全相同。可以使用您觉得更舒适的任何一种。现在,让我们看看各种配置选项:

设置 使用
ns 这是用于数据属性的命名空间值。默认为空。如果要为 jQuery Mobile-recognized 数据属性添加前缀,则可以在此处指定值。因此,例如,如果要使用data-jqm-role="page"而不是data-role="page",则可以将ns值配置为jqm
activeBtnClass 这只是设置在活动状态下按钮使用的类名。默认值为ui-btn-active
activePageClass 这设置了当前正在查看的页面的类名。默认值为ui-page-active
ajaxEnabled 我们之前讨论过 Ajax 既用于页面加载,也用于表单提交。如果你希望禁用此功能,请将此值设置为 false。默认情况下是true
allowCrossDomainPages 一个默认值为 false 的安全设置,将其设置为 true 允许通过 $.mobile.loadPage 加载来自另一个服务器的远程页面。通常仅在需要从另一个服务器加载内容的 PhoneGap 应用程序中需要。
autoInitializePage 通常情况下,jQuery Mobile 在加载时会运行 $.mobile.initializePage。这会显示渲染页面。(目前,这个特定功能并没有得到很好的文档记录。)如果你希望禁用此默认值,请将autoInitializePage设置为 false。你需要手动运行$.mobile.initializePage
defaultDialogTransition 指定显示或隐藏对话框时使用的过渡效果。默认值为 pop。可能的值包括:fade, flip, pop, slide, slidedownslideup
defaultPageTransition 类似于前一个选项,这个设置用于页面加载时的过渡效果。默认值为 slide,可能的选项与前一个选项类似。
gradea 用于确定什么才是一个“好”浏览器。这由 jQuery Mobile 处理,但如果你想否决框架,或定义必须满足的其他条件,你可以在这里提供一个返回布尔值(true 或 false)的函数。
hashListeningEnabled 指的是监听浏览器的 location.hash 属性的能力。jQuery Mobile 通常会处理这个,但如果将值设置为 false,你可以编写自己的代码来响应这些变化。
ignoreContentEnabled 通常情况下,jQuery Mobile 会自动增强任何可能的东西。你可以在某些情况下在控件级别禁用该功能,但也可以通过添加 data-enhance=true 告诉 jQuery Mobile 忽略特定容器内的所有内容。如果你使用了这个功能,那么你的配置必须设置 ignoreContentEnabledtrue。这告诉 jQuery Mobile 寻找并遵守该特定标志。默认情况下设置为 false,可以让 jQuery Mobile 更快地完成它的工作。
linkBindingEnabled jQuery Mobile 通常会监听所有链接点击。如果你希望全局禁用这个功能,可以通过这个设置来实现。
loadingMessage 这指定了页面加载时使用的文本。通常是“loading”,但你可能会在此处使用自定义代码来检查用户的语言环境,并使用特定的本地化版本。然而,消息通常是隐藏的。有关更多信息,请参阅下一个设置。
loadingMessageTextVisible 当页面由 jQuery Mobile 加载时,只会使用一个加载图形。如果你希望显示一条消息,将这个值设置为 true。默认值为 false
loadingMessageTheme 用于页面加载对话框的主题。默认值为 a
minScrollBack 当用户返回到页面时,jQuery Mobile 将尝试记住您在页面中滚动的位置。这在用户在访问另一个页面后返回到的大页面上可能很有用。默认情况下,如果滚动超过默认值 150,则会记住滚动位置。
pageLoadErrorMssage 如果加载页面时发生错误,则向用户显示的消息。默认为 Error Loading Page,但出于本地化原因(或其他任何原因),可能会更改。
pageLoadErrorMessageTheme 显示页面加载错误对话框时要使用的主题。默认值为 e
pushStateEnabled 告诉 jQuery Mobile 使用 HTML5 pushState 功能而不是基于哈希的方式进行页面导航。默认值为 true
subPageUrlKey jQuery Mobile 支持一个文件中的多个页面。为了使这些“虚拟”页面可书签化,jQuery Mobile 将在 URL 中追加一个值,该值包含前缀 ui-page。例如,ui-page=yourpage。此设置允许您自定义前缀。

这是相当多的选项,但通常您只需要配置其中一个或两个设置。让我们看一个简单的示例,其中使用了其中几个设置。Listing 8-1 是应用程序的主页。请注意,使用额外的脚本标签加载我们的配置:

Listing 8-1: test1.html
<!DOCTYPE html>
<html>
<head>
<title>Page Transition Test</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.6.4.min.js"></script>
<script src="img/config.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page" id="first">
<div data-role="header">
<h1>Dialog Test</h1>
</div>
<div data-role="content">
<p>
<a href="#page2">Another Page</a><br/>
<a href="test2.html">Yet Another Page</a><br/>
</p>
</div>
</div>
<div data-role="page" id="page2">
<div data-role="header">
<h1>The Second</h1>
</div>
<div data-role="content">
<p>
This is the Second. Go <a href="#first">first</a>.
</p>
</div>
</div>
</body>
</html>

文件包含两个页面,并链接到另一个 test2.html。该页面只提供一个返回链接,因此不会包含在文本中。现在让我们看看 config.js:

Listing 8-2: config.js
$(document).bind("mobileinit", function() {
$.mobile.defaultPageTransition = "fade";
$.mobile.loadingMessage="Fetching page...";
});

config.js 中,修改了两个设置 - 默认页面转换和页面加载消息。

在前一章中,我们讨论了表单以及 jQuery Mobile 如何自动增强控件。虽然您可以在 HTML 中禁止对控件的此增强,但还可以告诉 jQuery Mobile 一系列永远不要增强的控件。要设置此列表,请为 $.mobile.page.prototype.options.keepnative 指定一个值。该值应为一个选择器列表。与其中一个选择器匹配的任何字段都将不会被增强。

使用 jQuery Mobile 实用程序

现在我们已经讨论了 jQuery Mobile 的配置,请让我们看一下可用于您的应用程序的实用程序。这些是框架提供的实用程序,可在任何应用程序中使用。您可能不需要它们(或其中任何一个)在您的网站上,但知道它们存在可以帮助您节省将来的时间。

页面方法和实用程序

让我们开始查看与页面和页面之间导航相关的方法和实用程序:

  • $.mobile.activePage: 此属性是对当前页面的引用。

  • $.mobile.changePage(page,options): 此方法用于切换到另一个页面。第一个参数 page 可以是一个字符串(URL),也可以是 jQuery DOM 对象。options 参数是一个可选的键/值对对象。这些选项包括:

    • allowSamePageTransition: 通常情况下,jQuery Mobile 不会允许您转换到相同的页面,但如果设置为 false,则会允许这样做。

    • changeHash: 确定 URL 是否应该更改。

    • data: 传递给下一页的值的字符串或对象。

    • data-url: 用于浏览器中的 URL 的值。通常由用户要发送到的页面设置。你可以在这里覆盖它。

    • pageContainer: jQuery Mobile 将页面放置在作为所有页面的 的 DOM 项中。你可以绕过此自动收集并使用 DOM 中的另一个项。

    • reloadPage: 如果页面已经存在于浏览器中,jQuery Mobile 将从内存中获取它。将此设置为 true 将强制 jQuery Mobile 重新加载页面。

    • role: jQuery Mobile 通常会查找加载的页面的 data-role 属性。要指定另一个角色,请设置此选项。

    • showLoadMsg: 通常当页面被获取时,jQuery Mobile 会显示一个加载消息。你可以通过将此值设置为 false 来禁用此功能。

    • transition: 使用什么过渡效果。请记住,这可以在全局级别进行配置。

    • type: 我们之前提到过,jQuery Mobile 通过基于 Ajax 的请求加载新页面。type 选项允许你指定用于加载页面的 HTTP 方法。默认为 get

  • $.mobile.loadPage(page,options): 这是一个更低级别的函数,当 $.mobile.changePage 被传递一个字符串 URL 来加载时使用。它的第一个参数与 $.mobile.changePage 相同,但其选项限于 data, loadMsgDelay, pageContainer, reloadPage, roletype。这些选项与前一个选项中列出的相同,除了 loadMsgDelay。此值为框架尝试首先通过缓存获取页面提供时间。

  • $.mobile.showPageLoadingMsg()$.mobile.hidePageLoadingMsg(): 显示或隐藏页面加载消息。showPageLoadingMsg 函数允许自定义文本、主题和仅图标视图。

listing 8-2 中,演示了 $.mobile.changePage 的一个简单示例:

Listing 8-2: test3.html
<!DOCTYPE html>
<html>
<head>
<title>Page Tester</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page" id="third">
<div data-role="header">
<h1>Test</h1>
</div>
<div data-role="content">
<input type="button" id="pageBtn" value="Go to page">
</div>
</div>
<script>
$("#pageBtn").click(function() {
$.mobile.changePage("test2.html", {transition:"flip"});
});
</script>
</body>
</html>

页面只包含一个按钮。文件底部是一个 jQuery 事件监听器,用于监听该按钮。当点击时,使用 $.mobile.changePage 加载 test2.html,同时使用翻转过渡效果。

与路径和 URL 相关的实用程序

这些实用程序与应用程序的当前位置、URL 或路径相关:

  • $.mobile.path.isAbsoluteUrl$.mobile.path.isRelativeUrl: 这两个函数查看一个 URL 并允许你检查它们是完整的、绝对的 URL 还是相对的 URL。

  • $.mobile.path.isSameDomain(first url, second url): 允许你比较两个 URL,并确定它们是否在同一个域中。此方法将注意到 http 与 https 并正确地将它们视为不同的域。

  • $.mobile.path.makePathAbsolute(relative path, absolute path): 获取一个相对路径,将其与一个绝对路径进行比较,并返回相对路径的绝对路径版本。

  • $.mobile.path.makeUrlAbsolute(relative url, absolute url): 这个工具与前一个函数稍有不同,它处理绝对 URL。

  • $.mobile.path.parseUrl(url): URL 由许多不同的部分组成。此函数将接受完整或相对 URL,并返回一个包含以下属性的对象:hash、host、hostname、href、pathname、port、protocol 和 search。除了这些相当典型的 URL 属性外,该函数还返回以下属性:

    • authority: 包含用户名、密码和主机属性。

    • directory: 给定 URL 的路径部分,这将只返回目录。

    • domain: 包含 URL 的授权和协议部分。

    • filename: 返回 URL 的文件名部分。

    • hrefNoHash: 给定带有哈希的 URL,返回除哈希外的 href。

    • hrefNoSearch: 给定带有搜索属性的 URL,返回除搜索值外的 href。

    • usernamepassword: 包含 URL 中的用户名和密码(如果有)。

Listing 8-3 是一个 测试 应用程序。它包含表单字段,允许您测试先前讨论过的所有方法:

Listing 8-3: test4.html
<!DOCTYPE html>
<html>
<head>
<title>Path Tester</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.6.4.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page" id="third">
<div data-role="header">
<h1>Test</h1>
</div>
<div data-role="content">
<form>
<div data-role="fieldcontain">
<label for="isabsurl">Is Absolute URL?</label>
<input type="text" name="isabsurl" id="isabsurl" value="" />
<div id="isabsurlresult"></div>
</div>
<div data-role="fieldcontain">
<label for="isrelurl">Is Relative URL?</label>
<input type="text" name="isrelurl" id="isrelurl" value="" />
<div id="isrelurlresult"></div>
</div>
<div data-role="fieldcontain">
<label for="issamedomain">Is Same Domain?</label>
<input type="text" name="issamedomain" id="issamedomain" value="" />
<input type="text" name="issamedomain2" id="issamedomain2" value="" />
<div id="issamedomainresult"></div>
</div>
<div data-role="fieldcontain">
<label for="makepath">Make Path Absolute</label>
<input type="text" name="makepath" id="makepath" value="" placeholder="Relative Path" />
<input type="text" name="makepath2" id="makepath2" value="" placeholder="Absolute Path" />
<div id="makepathresult"></div>
</div>
<div data-role="fieldcontain">
<label for="makeurl">Make URL Absolute</label>
<input type="text" name="makeurl" id="makeurl" value="" placeholder="Relative URL" />
<input type="text" name="makeurl2" id="makeurl2" value="" placeholder="Absolute URL" />
<div id="makeurlresult"></div>
</div>
<div data-role="fieldcontain">
<label for="parseurl">Parse URL</label>
<input type="text" name="parseurl" id="parseurl" value="" />
<div id="parseurlresult"></div>
</div>
</form>
</div>
</div>
<script>
$("#isabsurl").keyup(function() {
var thisVal = $(this).val();
var isAbsUrl = $.mobile.path.isAbsoluteUrl(thisVal);
$("#isabsurlresult").text(isAbsUrl);
});
$("#isrelurl").keyup(function() {
var thisVal = $(this).val();
var isRelUrl = $.mobile.path.isRelativeUrl(thisVal);
$("#isrelurlresult").text(isRelUrl);
});
$("#issamedomain,#issamedomain2").keyup(function() {
var domainVal1 = $("#issamedomain").val();
var domainVal2 = $("#issamedomain2").val();
var isSameDomain = $.mobile.path.isSameDomain(domainVal1,domainVal2);
$("#issamedomainresult").text(isSameDomain);
});
$("#makepath,#makepath2").keyup(function() {
var pathVal1 = $("#makepath").val();
var pathVal2 = $("#makepath2").val();
var makePathResult = $.mobile.path.makePathAbsolute(pathVal1,pathVal2);
$("#makepathresult").text(makePathResult);
});
$("#makeurl,#makeurl2").keyup(function() {
var urlVal1 = $("#makeurl").val();
var urlVal2 = $("#makeurl2").val();
var makeUrlResult = $.mobile.path.makeUrlAbsolute(urlVal1,urlVal2);
$("#makeurlresult").text(makeUrlResult);
});
$("#parseurl").keyup(function() {
var thisVal = $(this).val();
var parsedUrl = $.mobile.path.parseUrl(thisVal);
var s = "";
for (k in parsedUrl) {
s+= k+"="+parsedUrl[k]+"<br/>";
}
$("#parseurlresult").html(s);
});
</script>
</body>
</html>

Listing 9-4 有点长,但实际上非常简单。每个 fieldcontain 块都由路径方法和实用工具的一个特定测试组成。在模板的下半部分,您可以看到我们已经使用 keyup 事件侦听器来监视这些字段的更改并运行每个测试。您可以使用此模板来查看这些方法如何根据不同的输入而反应。以下截图显示了一个示例:

路径和 URL 相关的实用工具

杂项实用程序

还有一些您可能想了解的其他实用程序:

  • $.mobile.fixedToolbars.hide()$.mobile.fixedToolbars.show(): 显示或隐藏固定工具栏。这两个实用程序都可以接受一个布尔参数,指定隐藏(或显示)动作是否立即发生。如果未指定(或传递 false),则工具栏将在隐藏或显示时进行动画处理。

  • $.mobile.silentScroll(position): 将页面滚动到特定的 y 位置。这里的 silent 一词指的是此方法会触发任何监听滚动事件的代码。

  • jqmData()jqmRemoveData(): 由于 jQuery Mobile 大量使用数据属性进行各种功能,因此应该用这些替代 jQuery 的数据函数的“常规”用法。它们处理识别对默认命名空间的任何更新。

jQuery 小部件和表单实用工具

我们已经多次提到,jQuery Mobile 会自动更新各种项目并支持诸如列表和可折叠内容之类的功能。但是,您可能会遇到的一件事是尝试使 jQuery Mobile 与页面渲染加载的内容一起工作。因此,例如,想象一下列表视图,通过一些 JavaScript 代码向其添加数据。Listing 8-4 展示了一个简单的示例。它有一个 listview,其中包含一些项目,但也有一个人可以通过其中一个表单添加新条目的表单:

Listing 8-4: test5.html
<!DOCTYPE html>
<html>
<head>
<title>List Updates</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page" id="third">
<div data-role="header">
<h1>List Updates</h1>
</div>
<div data-role="content">
<ul id="theList" data-role="listview" data-inset="true">
<li>Initial</li>
<li>Item</li>
</ul>
<form>
<div data-role="fieldcontain">
<label for="additem">New Item</label>
<input type="text" name="additem" id="additem" value="" />
</div>
<input type="button" id="testBtn" value="Add It">
</form>
</div>
</div>
<script>
$("#testBtn").click(function() {
var itemToAdd = $.trim($("#additem").val());
if(itemToAdd == "") return;
$("#theList").append("<li>"+itemToAdd+"</li>");
});
</script>
</body>
</html>

最初加载时,请注意一切似乎都很正常:

jQuery 小部件和表单实用工具

但是,以下屏幕截图显示了将项目添加到列表末尾时发生的情况:

jQuery 小部件和表单实用程序

正如您所见,新项目确实被添加到了列表的末尾,但是没有正确地绘制。这提出了一个关键问题。jQuery Mobile 仅对数据属性解析您的代码并一次性检查表单字段。在这样做之后,它认为自己的工作完成了。幸运的是,这些 UI 项更新有一种标准方法。对于我们的listview,只需在列表本身上调用listview方法就可以了。listview方法可用于将新列表转换为listview,或刷新现有的listview。要刷新我们的listview,我们只需修改代码,如下面的代码片段所示:

<script>
$("#testBtn").click(function() {
var itemToAdd = $.trim($("#additem").val());
if(itemToAdd == "") return;
$("#theList").append("<li>"+itemToAdd+"</li>");
$("#theList").listview("refresh");
});
</script>

您可以在test6.html中找到前一个代码片段。以下屏幕截图显示了应用程序如何处理新项目:

jQuery 小部件和表单实用程序

那个listview方法也可以用于全新的列表。考虑以下代码片段清单 8-5:

Listing 8-5: test7.html
<!DOCTYPE html>
<html>
<head>
<title>List Updates</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page" id="third">
<div data-role="header">
<h1>List Updates</h1>
</div>
<div data-role="content" id="contentDiv">
<input type="button" id="testBtn" value="Add A List">
</div>
</div>
<script>
$("#testBtn").click(function() {
$("#contentDiv").append("<ul data-role='listview' data- inset='true' id='theList'><li>Item One</li><li>Item Two</li></ul>");
$("#theList").listview();
});
</script>
</body>
</html>

在这个例子中,一个全新的列表被附加到div标签上。请注意,我们仍然包含适当的data-role。但是,仅此而已是不够的。我们在 HTML 插入后紧跟着调用listview方法来增强刚添加的列表。

对于其他字段也存在类似的 API。例如,添加到页面的新按钮可以通过在其上调用button()方法来增强。一般来说,假设对增强控件的任何更改都需要通过它们各自的 JavaScript API 进行更新。

概要

在本章中,我们(终于!)深入了解了一些 JavaScript。我们看了一下您如何配置各种 jQuery Mobile 设置,存在哪些实用程序,以及如何处理对增强控件的后渲染更新。

在下一章中,我们将继续使用 JavaScript,并查看您的代码可以监听的各种事件。

第九章:处理事件

在本章中,我们将看看 jQuery Mobile 中事件是如何工作的。虽然开发人员显然可以访问常规事件(按钮点击等),但 jQuery Mobile 也为开发人员提供了自己的事件来使用。

在本章中,我们将:

  • 讨论触摸、滑动、滚动和其他物理事件

  • 讨论页面事件

处理物理事件

在本章的第一部分,我们将专注于“物理”事件,或者与使用设备时的触摸和其他操作相关的事件。

提示

对于那些一直在使用常规浏览器测试 jQuery Mobile 的人,请注意,以下一些示例在桌面浏览器上可能无法正常工作。如果愿意,可以下载并安装各种手机模拟器。例如,Android 有一个支持创建虚拟移动设备的 SDK。苹果也有一种模拟 iOS 设备的方法。设置和安装这些模拟器超出了本章的范围,但这当然是一种选择。当然,您也可以使用真实的硬件设备。

物理事件包括以下内容:

  • taptaphold: tap 表示其听起来就像 — 网页上的快速物理触摸。 taphold 是一个较长时间的触摸。许多应用程序将使用两种不同的操作 — 一个用于 tap,另一个用于 taphold

  • swipe, swipeleftswiperight: 这些表示滑动,或者对大多数设备的手指移动。 swipe 事件是通用事件,而 swipeleftswiperight 表示特定方向的滑动。不支持向上或向下的滑动事件。

  • scrollstartscrollstop: 分别处理页面滚动的开始和结束。

  • orientationchange: 当设备方向改变时触发。

  • vclick、vmousedown、vmouseup、vmousemove、vmousecancelvmouseover: 所有这些都是“虚拟”事件,旨在屏蔽对触摸或鼠标点击事件的检查。由于这些主要只是点击和触摸事件的别名,因此不会进行演示。

现在我们已经列出了基本的物理事件,让我们开始看一些示例。 清单 9-1 演示了 taptaphold 事件的一个简单示例:

Listing 9-1: test1.html
<!DOCTYPE html>
<html>
<head>
<title>Tap Tests</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page" id="first">
<div data-role="header">
<h1>Tap Tests</h1>
</div>
<div data-role="content">
<p>
Tap anywhere on the page...
</p>
<p id="status"></p>
</div>
</div>
<script>
$("body").bind("tap", function(e) {
$("#status").text("You just did a tap event!");
});
$("body").bind("taphold", function(e) {
$("#status").text("You just did a tap hold event!");
});
</script>
</body>
</html>

该模板相当简单。页面上有一些解释性文本,要求用户点击它。其下是一个空段落。请注意,文档末尾有两个绑定。一个监听 tap,另一个监听 taphold。用户可以执行任一操作,并显示不同的状态消息。尽管相当简单,但这给了您一个很好的想法,即根据用户按住手指的时间长短做出不同的响应。(taphold 事件触发的时间大约为一秒):

处理物理事件

现在让我们来看 清单 9-2,一个关于滑动事件的示例:

Listing 9-2: test2.html
<!DOCTYPE html>
<html>
<head>
<title>Swipe Tests</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/ jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page" id="first">
<div data-role="header">
<h1>Swipe Tests</h1>
</div>
<div data-role="content">
<p>
Swipe anywhere on the page...
</p>
<p id="status"></p>
</div>
</div>
<script>
$("body").bind("swipe", function(e) {
$("#status").append("You just did a swipe event!<br/>");
});
$("body").bind("swipeleft", function(e) {
$("#status").append("You just did a swipe left event!<br/>");
});
$("body").bind("swiperight", function(e) {
$("#status").append("You just did a swipe right event!<br/>");
});
</script>
</body>
</html>

这个例子与前一个例子非常相似,只是现在我们的事件处理程序监听swipe, swipeleftswiperight。一个重要的区别是我们附加到状态 div 而不是简单地设置它。为什么呢?swiperightswipeleft事件自动是一个滑动事件。如果我们简单地设置段落中的文本,一个将覆盖另一个。下面的截图显示了设备在几次滑动后的外观:

使用物理事件

更复杂的例子呢?考虑以下代码片段,9-3 清单

Listing 9-3: test3.html
<!DOCTYPE html>
<html>
<head>
<title>Swipe Tests</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page" id="first">
<div data-role="header">
<h1>First</h1>
</div>
<div data-role="content">
<p>
Swipe to navigate
</p>
</div>
</div>
<div data-role="page" id="second">
<div data-role="header">
<h1>Second</h1>
</div>
<div data-role="content">
<p>
Swipe to the right...
</p>
</div>
</div>
<script>
$("body").bind("swipeleft swiperight", function(e) {
var page = $.mobile.activePage[0];
var dir = e.type;
if(page.id == "first" && dir == "swipeleft") $.mobile.changePage("#second");
if(page.id == "second" && dir == "swiperight") $.mobile.changePage("#first");
});
</script>
</body>
</html>

在这个例子中,我们有一个包含两个单独页面的文件,一个页面的 id 为first,另一个页面的 id 为second。注意我们没有链接。那么我们如何导航呢?用滑动!我们的事件处理程序现在同时监听swipeleftswiperight。我们首先使用$.mobile.activePage获取活动页面,如第八章 jQuery Mobile 中的 JavaScript 配置和实用工具中所述,关于方法和实用工具。末尾的[0]表示该值实际上是一个 jQuery 选择器。使用[0]会获取实际的 DOM 项。事件类型将是swipeleftswiperight。一旦我们知道了这一点,我们就可以根据用户当前所在的页面和他们滑动的方向积极地移动用户。

现在让我们来看一下滚动。你可以检测滚动何时开始以及何时结束。9-4 清单是另一个这样操作的简单示例:

Listing 9-4: test4.html
<!DOCTYPE html>
<html>
<head>
<title>Scroll Tests</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page" id="first">
<div data-role="header">
<h1>Scroll Tests</h1>
</div>
<div data-role="content">
<p>
Scroll please....<br/>
<br/>
<br/>
(Many <br/> tags removed to save space!)
<br/>
<br/>
</p>
<p id="status"></p>
</div>
</div>
<script>
$("body").bind("scrollstart", function(e) {
$("#status").append("Start<br/>");
});
$("body").bind("scrollstop", function(e) {
$("#status").append("Done!<br/>");
});
</script>
</body>
</html>

这个模板与test1.html,即点击测试器非常相似,只是现在我们监听了scrollstartscrollstop。还要注意<br/>标签的列表。在真实的源文件中,这些标签有很多。这将确保在测试时页面确实是可滚动的。当滚动开始和结束时,我们只是将其附加到另一个状态div。(请注意,当前将 DOM 操作列为在监听scrollstart时存在错误。前面的例子在 iOS 上可能无法工作,但在 Android 上工作正常。)

现在让我们来看一下方向。虽然前面的例子大部分可以在你的桌面上测试,但你肯定需要一个真实的移动设备来测试下一个例子:

Listing 9-5: test5.html
<!DOCTYPE html>
<html>
<head>
<title>Orientation Tests</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page" id="first">
<div data-role="header">
<h1>Orientation Tests</h1>
</div>
<div data-role="content">
<p>
Tilt this sideways!
</p>
<p id="status"></p>
</div>
</div>
<script>
$(window).bind("orientationchange", function(e,type) {
$("#status").html("Orientation changed to "+e.orientation);
});
</script>
</body>
</html>

前一个代码清单的关键部分是最后的 JavaScript,特别是用于更改方向的事件侦听器。这实际上不是 jQuery Mobile 支持的事件,而是浏览器本身支持的事件。一旦事件侦听器被附加,你可以根据设备的方向进行任何操作。以下截图是演示:

使用物理事件

处理页面事件

现在我们已经讨论了物理类型事件,是时候将注意力转向页面事件了。请记住,jQuery Mobile 有自己的页面概念。为了在 jQuery Mobile 中给开发人员更多控制页面工作的能力,支持了许多页面事件。并非所有事件都一定在日常开发中有用。一般来说,页面事件可以分为以下几类:

  • load:这些是与页面加载相关的事件。它们是pagebeforeload,pageloadpageloadfailed。pagebeforeload在请求页面之前触发。您的代码可以根据逻辑批准或拒绝此请求。如果加载页面,则会触发pageload。相反,pageloadfailed将在任何未完成的加载上触发。

  • change:这些事件与从一个页面更改到另一个页面有关。它们是:pagebeforechange,pagechangepagechangefailed。与以前一样,pagebeforechange函数充当编程方式拒绝事件的一种方式。如果完成,将触发pagechangefailed事件。pagebeforechangepagebeforeload事件之前触发。pagechange将在显示页面后触发。

  • transition:与从一个页面转换到另一个页面相关的事件。它们是:pagebeforeshow,pageshow,pagebeforehide,pagehidepagebeforeshowpagebeforehide在其相关事件之前运行,但与pagebeforeloadpagebeforechange不同,它们实际上不能阻止下一个事件的发生。

  • init:正如本书中多次显示的那样,jQuery Mobile 对基本 HTML 执行多次更新,以使其优化为移动显示。这些是与初始化相关的事件。您可以监听的事件是:pagebeforecreate,pagecreatepageinit。pagebeforecreate在您的控件上的任何自动更新触发之前触发。这允许您在布局由 jQuery Mobile 更新之前通过 Javascript 操纵您的 HTML。pagecreate在页面内容存在于 DOM 中之后触发,但仍然在 jQuery Mobile 更新布局之前触发。官方文档建议这是进行任何自定义小部件处理的地方。最后,pageinit将在初始化完成后运行。

  • remove:此类别有一个事件pageremove。在 jQuery Mobile 从 DOM 中删除非活动页面之前触发此事件。您可以监听此事件以防止框架删除页面。

  • layout:最后一个类别与布局相关,有一个事件updatelayout。这通常是由其他布局更改触发的一种方式,用于通知页面需要更新自身。

这还真是不少啊!看待这些事件的一个简单方法就是简单地听取它们的全部。在列表 9-6中,我们有一个这样的简单示例:

Listing 9-6: test_page.html
<!DOCTYPE html>
<html>
<head>
<title>Page Event Tests</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page" id="first">
<div data-role="header">
<h1>Page Event Tests</h1>
</div>
<div data-role="content">
<p>
<a href="#page2" data-role="button">Go to Page 2</a>
<a href="test_pagea.html" data-role="button"> Go to Page 3</a>
<a href="test_pageb.html" data-role="button"> Go to Page 4</a>
<a href="test_pageDOESNTEXIST.html" data-role="button"> Go to Page Failed</a>
</p>
</div>
</div>
<div data-role="page" id="page2">
<div data-role="header">
<h1>Page Event Tests</h1>
</div>
<div data-role="content">
<p>
<a href="#first" data-role="button">Go to Page 1</a>
<a href="test_pagea.html" data-role="button"> Go to Page 3</a>
<a href="test_pageb.html" data-role="button"> Go to Page 4</a>
</p>
</div>
</div>
<script>
$(document).bind("pagebeforeload pageload pageloadfailed pagebeforechange pagechange pagechangefailed pagebeforeshow pagebeforehide pageshow pagehide pagebeforecreate pagecreate pageinit pageremove updatelayout", function(e) {
console.log(e.type);
});
</script>
</body>
</html>

这个模板是一个四页、三文件的简单应用程序的一部分,它有按钮链接到其他每一页。其他页面可以在你下载的 ZIP 文件中找到。为了测试这个应用程序,你应该使用支持控制台的桌面浏览器。任何版本的 Chrome,最近的 Firefox 浏览器(或带有 Firebug 的 Firefox)和最新的 Internet Explorer。浏览器控制台的完整说明无法在本章中适用,但你可以把它看作是一个隐藏的调试日志,用于记录事件和其他消息。在这种情况下,我们已经告诉 jQuery 监听我们所有的 jQuery Mobile 页面事件。然后我们将特定的事件类型记录到控制台。点击了一些东西之后,以下屏幕截图显示了在 Chrome 浏览器中控制台日志的样子:

处理页面事件

在 Chrome 中打开控制台很简单。点击浏览器右上角的扳手图标。选择工具然后选择JavaScript 控制台。在测试这些文件之前打开控制台,你可以实时监控页面事件的发生情况。

$(document).ready怎么样?

如果你是一个 jQuery 用户,你可能会好奇$(document).ready在 jQuery Mobile 站点中是如何发挥作用的。几乎所有的 jQuery 应用程序都使用$(document).ready进行初始化和其他重要的设置操作。然而,在 jQuery Mobile 应用程序中,这样做效果不佳。由于使用 Ajax 加载页面,$(document).ready只对第一个页面有效。因此,在过去使用$(document).ready的情况下,应该使用pageInit事件。

创建一个真实的例子

那么真实的例子呢?我们的下一组代码将演示如何创建一个简单但动态的 jQuery Mobile 网站。内容将通过 Ajax 加载。通常这将是动态数据,但出于我们的目的,我们将使用简单的静态 JSON 数据文件。JSON,代表 JavaScript 对象表示法,是一种将复杂数据表示为简单字符串的方法。列表 9-7是应用的首页:

Listing 9-7: test_dyn.html
<!DOCTYPE html>
<html>
<head>
<title>Test Dynamic</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/ jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page" id="homepage">
<div data-role="header">
<h1>Dynamic Pages</h1>
</div>
<div data-role="content">
<ul id="peopleList" data-role="listview" data-inset="true"></ul>
</div>
</div>
<script>
$("#homepage").bind("pagebeforecreate", function(e) {
//load in our people
$.get("people.json", {}, function(res,code) {
var s = "";
for (var i = 0; i < res.length; i++) {
s+="<li><a href='test_people.html ?id="+res[i].id+"'>"+res[i].name+"</a></li>";
}
$("#peopleList").html(s).listview("refresh");
}, "json");
});
$("#personpage").live("pagebeforeshow", function(e) {
var thisPage = $(this);
var thisUrl = thisPage.data("url");
var thisId = thisUrl.split("=")[1];
$.get("person"+thisId+".json", {}, function(res, code) {
$("h1",thisPage).text(res.name);
s = "<p>"+res.name +" is a "+res.gender+" and likes "+res.hobbies+"</p>";
$("#contentArea", thisPage).html(s);
}, "json");
});
</script>
</body>
</html>

这个 jQuery Mobile 页面的第一印象是,实际内容几乎不存在。至少在 jQuery Mobile 页面的内容块中是这样的。有一个listview但实际内容却不存在。那么内容从哪里来呢?在页面底部,你可以看到两个事件监听器。现在让我们只关注第一个。

这里的代码绑定到了 jQuery Mobile 为页面触发的pagebeforecreate事件。我们已经告诉 jQuery Mobile 在创建页面之前运行此事件。这个事件将运行一次且仅运行一次。在这个事件中,我们使用 jQuery 的get功能对文件people.json进行了一个 Ajax 请求。该文件只是一个以 JSON 格式表示的名字数组。

[{"id":1,"name":"Raymond Camden"},{"id":2,"name":"Todd Sharp"},{"id":3,"name":"Scott Stroz"},{"id":4,"name":"Dave Ferguson"},{"id":5,"name":"Adam Lehman"}]

每个名称都有一个 ID 和实际的名称值。当通过 jQuery 加载时,这将转换为一组实际的简单对象。回顾事件处理程序,您会发现我们只需循环遍历此数组并创建表示一组li标签的字符串。请注意,每个都有一个指向test_people.html的链接,以及一个动态名称。还请注意链接本身是动态的。它们包括从 JSON 字符串中检索到的每个人的 ID 值:

创建一个真实的例子

早些时候提到过,但请注意调用listview("refresh")

$("#peopleList").html(s).listview("refresh");

没有listview("refresh")部分,我们添加到列表视图的项目将无法正确设置样式。

让我们快速看看下一个test_people.html

Listing 9-8: test_people.html
<!DOCTYPE html>
<html>
<head>
<title>Test Dynamic</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery- 1.7.1.min.js"></script>
<script src="img/ jquery.mobile.min.js"></script>
</head>
<body>
<div data-role="page" id="personpage">
<div data-role="header">
<h1></h1>
</div>
<div data-role="content" id="contentArea">
</div>
</div>
</body>
</html>

与我们的上一页一样,这一页几乎没有内容。请注意,标题和内容区域都是空白的。但是,如果您记得test_dyn.html中的第二个事件处理程序,我们支持在这里加载内容。这次我们使用了pagebeforeshow事件。为什么?我们希望在每次显示页面之前运行此代码。我们需要知道要加载的特定人员是谁。如果您记得,人员的 ID 是通过 URL 传递的。我们可以通过页面对象上存在的数据属性url获取它。这返回完整的 URL,但我们只关心它的末尾,即我们的 ID。因此,我们拆分字符串并抓取最后一个值。一旦我们有了,我们就可以为每个人加载特定的 JSON 文件。此文件名的形式为personX.json,其中X是 1 到 5 的数字。以下代码行是一个示例:

{"name":"Raymond Camden","gender":"male","hobbies":"Star Wars"}

显然,真实的人物对象会有更多的数据。一旦我们获取了这个字符串,我们就可以解析它并将结果布局在页面上:

创建一个真实的例子

总结

在本章中,我们研究了 jQuery Mobile 应用程序可以监听和响应的事件。这些事件包括物理类型(滚动、方向、触摸)和基于页面的事件。

在下一章中,我们将看看 jQuery Mobile 站点如何主题化 - 包括开箱即用的主题和自定义主题。

第十章:进一步了解 Notekeeper 移动应用程序

在这一章中,我们将开始将迄今为止学到的关于列表、表单、页面和内容格式化的所有内容组合成一个可用的“移动应用程序”;即 Notekeeper 应用程序。

在本章中,我们将:

  • 使用表单接受用户输入

  • 使用 HTML5 localStorage 功能在本地存储用户输入的数据

  • 演示如何动态地向页面添加、编辑和删除项目

什么是移动应用程序?

在编写我们的第一个移动应用程序之前,也许我们应该定义一下什么是移动应用程序。维基百科说,移动应用程序是为小型低功耗手持设备开发的软件,如个人数字助理、企业数字助理或移动电话。虽然 jQuery Mobile 应用程序是用 HTML、CSS 和 JavaScript 编写的,但这并不妨碍它们成为复杂的软件。它们肯定是针对移动设备开发的。

一些评论家可能会指出,除非“安装”,否则它实际上不能成为软件。正如您将在本书的后面看到的,与开源库 PhoneGap 配合使用时,jQuery Mobile 应用程序实际上可以安装在各种设备上(包括 iOS、Android 和 Windows Mobile)。这意味着您将能够兼得。您可能会问自己,使用 jQuery Mobile 编写的代码是否可以被视为软件,正如您将在本章中了解到的那样,答案是肯定的。

设计您的第一个移动应用程序

任何软件的目标都是满足需求。Gmail 通过让用户摆脱单一计算机并让他们可以从任何 Web 浏览器检查电子邮件来满足需求。Photoshop 通过允许用户以前所未有的方式操纵照片来满足需求。我们的 Notekeeper 应用程序通过允许我们记录简单的笔记以供以后参考来满足需求。我知道,与之相比有点令人失望,但我们必须从某个地方开始对吧?

在构建软件时,最好花时间事先撰写项目的规格说明:它将做什么,它将是什么样子,以及它应该具有什么。记住,如果你不知道你在构建什么,你怎么会知道它是否完成了?

列出要求

我们已经知道我们的应用想要做什么,记笔记。问题在于有很多种方式可以构建一个笔记应用,因此必须勾勒出我们想要的功能。不多不少,但目前足够。对开发人员来说,一个事实是我们的应用永远不会“完成”,它们只是暂时“完成”。对于 Notekeeper,我们决定我们想要用我们的应用程序做以下三件事:

  • 添加笔记

  • 显示笔记列表

  • 查看笔记/删除笔记

在决定我们的应用程序需要完成哪些任务之后,我们需要决定它将如何完成这些任务。最简单的方法就是简单地将这些事情写成一个列表。通过将每个部分细分为更小的部分,我们使它更容易理解,并且看到我们需要做些什么才能让它工作。这就像得到去你最喜欢的餐厅的指南一样;这里拐个弯,那里转个圈,你转眼间就坐在餐桌前了。让我们看看我们希望 Notekeeper 做什么,以及下面的部分和部件:

  • 添加一个注释(表单)

    • 一个表单容器。所有用户输入的小部件都被包装成一个表单。

    • 一个标题,注释的名称。这也将用于显示现有的注释。

    • 注释本身。注释的内容或主体。

    • 保存按钮。这个按钮会触发实际的保存操作。

  • 显示注释列表的能力(列表视图)

    • 包含注释标题的行项。此行应该是指向包含注释主体的页面的链接。

    • 一个部分标题行可能很好。

  • 查看注释的能力,并删除注释(标签,段落,按钮)

    • 标题的标签

    • 包含注释内容的段落

    • 一个标有删除的按钮

    • 返回按钮

制作线框图

现在我们已经列出了我们的应用程序的功能,那么我们如何勾画出每一部分,以便我们知道我们想要的是什么样子?如果你的艺术功底不好,或者你连一个竖直线都画不出来,不要担心。如果你有尺子,可以使用尺子,或者考虑使用微软 Excel 或 PowerPoint。你只需要能够画一些框和一些文本标签。

设计添加注释线框图

现在,添加注释部分怎么样?我们决定它需要一个标题,一个注释框和一个提交按钮。表单是一个不可见的容器,所以我们不需要画出来:

设计添加注释线框图

显示注释框架

列表视图是移动开发的一个重要部分。这是将类似项目简单地分组在一起的最简单方法,另外它还提供了许多额外的功能,比如滚动和内置图片链接。我们将使用列表视图来显示我们的注释列表:

显示注释框架

查看注释/删除按钮框架

最后,一旦我们添加了一个注释,我们需要能够删除证据,我是说清除旧注释以为新注释腾出空间。请注意,我们还勾画了一个返回按钮。一旦你开始看到事情摆放出来,你会发现你忘记了一些非常重要的事情(比如能够返回到上一页):

查看注释/删除按钮框架

编写 HTML

现在我们的线框图已经完成,我们对它们感到满意,是时候将铅笔画变成 1 和 0 了。由于我们的应用程序相对简单,HTML 中的任何内容都不应该难倒你。毕竟,你已经过了书的一半了,而且你应该能够做到这些事情。

你所提出的 HTML 应该看起来与下面的代码片段非常相似。让我们一起来检查一下:

Listing 10-1: notekeeper.html
<!DOCTYPE html>
<html>
<head>
<title>Notekeeper</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<script src="img/jquery-1.6.4.js"></script>
<script src="img/ jquery.mobile.min.js"></script>
<script src="img/application.js"></script>
</head>
<body>
<div data-role="page">
<div data-role="header">
<h1>Notekeeper</h1>
</div>
<div data-role="content">
<form>
<div>
<input id="title" type="text" placeholder="Add a note" />
</div>
<div>
<textarea id="note" placeholder="The content of your note"></textarea>
</div>
<div class="ui-grid-a">
<div class="ui-block-a">
<input id="btnNoThanks" type="submit" value="No Thanks" />
</div>
<div class="ui-block-b">
<input id="btnAddNote" type="button" value="Add Note" />
</div>
</div>
</form>
<ul id="notesList" data-role="listview" data-inset="true">
<li data-role="list-divider">Your Notes</li>
<li id="noNotes">You have no notes</li>
</ul>
</div>
<div data-role="footer" class="footer-docs">
<h5>Intro to jQuery Mobile</h5>
</div>
</div>
</body>
</html>

我们的笔记管理应用程序将使用单个 HTML 文件(notekeeper.html)和单个 JavaScript 文件(application.js)。直到这一点,您编写的代码都不需要 JavaScript,但是一旦您开始编写更复杂的应用程序,JavaScript 就会成为必需品。在您的网络浏览器中预览 列表 10-1 中的 HTML,您应该会看到类似以下截图的内容:

编写 HTML

请注意,我们在同一个页面上显示添加笔记表单和查看笔记。在移动应用程序开发中,尽可能压缩东西是个好主意。不要将这个作为硬性规则,但由于我们的应用程序很简单,把这两部分放在一起是可以接受的决定,只要它们清晰地标记出来。你可以看到,这个页面满足了我们为添加笔记和显示现有笔记设定的所有要求。它有一个标题输入字段,一个笔记输入字段,一个保存按钮,并且整个东西都包裹在一个表单容器中。它还有一个列表视图,用于显示我们添加笔记后的笔记。这里看不到的是一个删除按钮,但一旦我们添加了第一个笔记并查看详细页面,它就会显示出来。

使用 JavaScript 添加功能

正如本书所提到的,您不需要编写任何 JavaScript 就能从 jQuery Mobile 中获得物有所值。但是随着您在 jQuery Mobile 中的经验不断增加,您将开始看到 JavaScript 可以为您的项目增加多少附加值。在我们查看代码之前,让我们谈谈它将如何结构化。如果您有任何网络设计或开发经验,您可能已经看到过 JavaScript。毕竟,它从 1995 年就开始存在了。问题是,JavaScript 有很多种不同的方法来做同样的事情,而不是所有方法都是好的。

这个应用程序中的 JavaScript 代码将使用所谓的设计模式。这只是一个花哨的术语,用来指定代码的某种结构。使用现有设计模式的主要原因有三个:

  • 它帮助我们的代码保持组织和整洁。

  • 它防止我们编写的变量和函数被我们可能添加的任何其他代码意外覆盖或更改。也许是一个 jQuery 插件,或者是从第三方网站加载的代码。

  • 它将帮助未来的开发人员更快地适应你的代码。你在开发下一个 Facebook 的时候有考虑到未来的开发人员吗?

在我们深入了解完整代码之前,让我们先来看一个非常简单的实现这个设计模式的示例:

Listing 10-2: kittyDressUp.js
$(document).ready(function(){
// define the application name
var kittyDressUp = {};
(function(app){
// set a few variables which can be used within the app
var appName = 'Kitty Dress Up';
var version = '1.0';
app.init = function(){
// init is the typical name that developers give for the
// code that runs when an application first loads
// use whatever word you prefer
var colors = app.colors();
}
app.colors = function(){
var colors = ['red','blue','yellow','purple'];
return colors;
}
app.init();
})(kittyDressUp);
});

如果您熟悉 JavaScript 或 jQuery,您可能会看到一些您熟悉的元素。对于那些不熟悉 jQuery 或 JavaScript 的读者,我们将逐行审查这个示例。KittyDressUp.js 以 jQuery 的最好朋友开头。包含在花括号内的任何代码都会等到文档或 HTML 页面完全加载后再执行。这意味着您,开发人员,可以确保您的代码在页面上需要的一切都加载完成后才运行:

$(document).ready({
// I'm ready captain!
});

简单来说,下一行创建了一个名为 kittyDressUp 的变量,并将其赋值为空对象的值。但是,在我们的代码中,这个新对象将包含我们的整个应用程序:

// define the application name
var kittyDressUp = {};

下面的声明是 Kitty Dress Up 应用程序的核心。它创建了一个接受单个参数的函数,然后立即调用自身,并传入我们在前一行中创建的空对象。这个概念称为自执行函数,它是使外部代码无法干扰我们的应用程序的方法。

(function(app){
// define the app functionality
})(kittyDressUp);

接下来的两行设置了一些只能从我们应用程序的上下文或范围中访问的变量:

// set a few variables which can be used within the app
var appName = 'Kitty Dress Up';
var version = '1.0';

最后,最后几行设置了两个在应用程序中可用的函数。您可以看到每个函数都被分配了一个在更大应用程序范围内的名称。app 变量是函数所在的地方,. 后面的单词是函数名称。请注意,在 init 函数内部,我们正在调用同一应用程序内的另一个函数,app.colors()。我们也可以引用我们在顶部定义的任何变量。

app.init = function(){
// init is the typical name that developers give for the
// code that runs when an application first loads
// use whatever word you prefer
var colors = app.colors();
}
app.colors = function(){
var colors = ['red','blue','yellow','purple'];
return colors;
}
app.init();

请记住,app 是传递给自执行函数的参数名称,其值为空对象。作为整体,这几行代码创建了一个名为 kittyDressUp 的对象,其中包含两个变量(appNameversion),以及两个函数(initcolors)。这个示例以及 Notekeeper 的代码都是简单的示例,但它们说明了您可以如何将代码包装成离散包以用于更大应用程序的各个部分。事实上,在 kittyDressUp.js 运行之后,您甚至可以将 kittyDressUp 传递到另一组代码中以供使用。

哎呀... 大家休息五分钟,你们赚了它。

存储 Notekeeper 数据

现在我们从五分钟的休息中回来了,是时候卷起袖子开始为我们的应用程序添加功能了。虽然我们已经讨论了我们希望 Notekeeper 的行为方式,但我们还没有讨论到存储笔记数据的核心问题。有几种可能性,都有利弊。让我们列出它们:

  • 数据库(MySQL、SQL Server、PostgreSQL): 虽然数据库是理想的解决方案,但它对我们的应用程序来说有点复杂,它需要互联网连接,并且您需要一个服务器端组件(ColdFusion、PHP、.NET)作为中间人将笔记保存到数据库中。

  • 文本文件: 文本文件非常棒,因为它们占用的空间很小。问题在于作为 Web 应用程序,Notekeeper 无法将文件保存到用户的设备上。

  • localStorage: localStorage 相对较新,但它迅速成为一个很好的选择。它以键/值对的形式存储信息在用户的设备上。它有大小限制,但对于纯文本来说相当大,大多数现代浏览器都支持它,并且可以在离线模式下使用。

使用 localStorage

为了本章的目的,我们将选择localStorage作为我们的首选方法。让我们快速看一下其行为,这样当你看到它时,你就会熟悉它。如前所述,localStorage的工作原理是存储键/值对中的数据。将值保存到localStorage有两种方式,无论你选择哪一种,都很容易:

localStorage.setItem('keyname','this is the value I am saving');

localStorage['keyname'] = 'this is the value I am saving';

选择哪个版本完全取决于个人偏好,但因为输入较少,我们将使用第二种方法,方括号。我们将遇到的一个问题是,localStorage无法存储如数组或对象之类的复杂数据。它只能存储字符串。这是一个问题,因为我们将把所有数据存储在一个变量中,以便始终知道其位置。别担心,我们可以欺骗localStorage,使用一个名为stringify()的内置函数将我们的复杂对象转换为其自身的字符串表示。

以下代码片段显示了它是如何工作的:

// create our notes object
var notes = {
'note number one': 'this is the contents of note number one', 'make conference call': 'call Evan today'
}
// convert it to a string, then store it.
localStorage['Notekeeper'] = JSON.stringify(Notekeeper);

检索值与设置值一样简单,并且也提供两个选项。通常需要定义一个变量来接收localStorage变量的内容。

var family = localStorage.getItem('my family');

var family = localStorage['my family'];

如果您正在检索复杂的值,则必须在使用变量内容之前执行另一步。正如我们刚才提到的,要存储复杂的值,您必须首先使用stringify()函数,它有一个称为parse()的相对应函数。parse()函数接受包含该复杂对象的字符串,并将其转换回纯粹的 JavaScript。它的用法如下:

var myFamily = ['andy', 'jaime', 'noelle', 'evan', 'mason'];
localStorage['family'] = JSON.stringify(myFamily);
var getFamily =JSON.parse(localStorage['family']);

最后,如果你想完全删除该密钥,那么你可以在单行代码中完成,有两种选择:

localStorage.removeItem('my family');

delete localStorage[my family'];

值得注意的是,如果您尝试检索在localStorage中不存在的密钥,JavaScript 不会引发错误。它只会返回“未定义”,这是 JavaScript 表示“抱歉,什么也没有”的方式。以下代码片段是一个示例:

var missing = localStorage['yertl the turtle'];
console.log(missing);
// returns undefined

有效使用样板文件

在我们开始构建 JavaScript 文件之前,还有一件事情。在我们的应用程序中,我们只会有一个 JavaScript 文件,它将包含整个代码库。这对于像我们这样的小型应用程序来说是可以的,但对于更大的应用程序来说不是一个好主意。最好将项目分解为不同的部分,然后将每个部分放入它们自己的文件中。这样做可以使开发团队更容易地协同工作(例如,Noelle 负责登录流程,而 Mason 则负责供应商列表)。它还使每个文件变得更小且更容易理解,因为它只涉及整体的一部分。当您希望应用程序的所有部分具有相似的结构和设计时,最好的方法是从一个模板开始每个部分。我们将为我们应用程序的唯一文件使用一个模板(你可以在以下代码片段中看到,Listing 10-3)。你可能会注意到它看起来非常类似于 kittyDressUp 示例,你是对的:

Listing 10-3: application.js
$(function(){
// define the application
var Notekeeper = {};
(function(app){
// variable definitions go here
app.init = function(){
// stuff in here runs first
}
app.init();
})(Notekeeper);
});

构建添加注释功能

最后,我们可以开始构建了!由于要显示不存在的笔记列表很困难,更不用说删除笔记了,我们将首先编写 添加注释 功能。用户要能够添加注释,他们必须输入标题、注释内容,然后点击提交按钮。所以我们从那里开始。

添加绑定

我们将在 app.init() 函数定义下创建一个新的、空的函数块。它应该看起来类似于以下代码行:

app.bindings = function(){
}

绑定函数将包含在我们的应用程序中当用户执行某些操作时需要触发的任何代码片段,例如点击提交按钮或删除按钮。我们将这些代码片段组合在一起以便组织。在 bindings() 函数内部,我们将添加以下行。这将在用户单击 添加注释 表单的提交按钮时触发:

// set up binding for form
$('#btnAddNote').bind('click', function(e){
e.preventDefault();
// save the note
app.addNote(
$('#title').val(),
$('#note').val()
);
});

jQuery 的 val() 函数是一个简写方法,用于获取任何表单输入字段的当前值。

关于这个新添加的一些说明:

  • 当使用 jQuery 时,总会有更多的方法来完成某件事情,在大多数情况下,你只需选择自己喜欢的方法即可(它们通常具有相同的性能)。你可能更熟悉 $('#btnAddNote').click(),那也完全可以。

  • 请注意,click 函数接受一个参数:e,它是事件对象(在本例中是点击事件)。我们调用 e.preventDefault() 来阻止在此元素上发生标准点击事件,但仍允许其余代码继续运行。你可能已经看到其他开发人员使用 return false,但 jQuery 最佳实践建议使用 e.preventDefault()

  • 在点击绑定中,我们调用 addNote 函数,并将用户输入的标题和注释传递给它。空白不重要,仅仅是为了更容易看到我们在做什么。

即使我们已经将绑定添加到我们的代码中,如果你现在运行应用程序,当你点击添加笔记按钮时什么也不会发生。原因是还没有任何东西调用bindings()函数。在init()函数内添加以下行,然后你就可以准备好了:

app.init = function(){
app.bindings();
}

收集和存储数据

接下来,在app.bindings下面添加另一个新的空函数块:

app.addNote = function(title, note){
}

现在,因为我们将所有的笔记都存储在localStorage的一个键中,我们首先需要检查是否已经存在任何笔记。从localStorage中检索 Notekeeper 键,将其保存到一个变量中,然后进行比较。如果我们要求的键的值是一个空字符串或undefined,我们将需要创建一个空对象。如果有一个值,那么我们将取出该值并使用parse()函数将其转换为 JavaScript:

var notes = localStorage['Notekeeper'];
if (notes == undefined || notes == '') {
var notesObj = {};
} else {
var notesObj = JSON.parse(notes)
}

注意我们期望将两个变量传递给addNote()函数,titlenote。接下来,我们用破折号替换标题中的任何空格,这样某些浏览器更容易理解文本字符串。然后我们将键值对放入我们新创建的笔记对象中:

notesObj[title.replace(/ /g,'-')] = note;

JavaScript 的replace方法使字符串操作非常简单。它作用于一个字符串,接受一个搜索项和一个替换项。搜索项可以是一个简单的字符串,也可以是一个复杂的正则表达式。

下一步是将我们的notesObj变量stringify()并放入localStorage中。然后我们清除两个输入字段的值,以便用户更轻松地输入另一个笔记。在构建软件时,一般在添加或删除内容后将界面恢复到原始状态是一个不错的举措:

localStorage['Notekeeper'] = JSON.stringify(notesObj);
// clear the two form fields
$note.val('');
$title.val('');
//update the listview
app.displayNotes();

所有这些变量定义对你来说应该很熟悉,也许有一个例外,我们应该指出。许多 jQuery 开发人员喜欢为包含 jQuery 对象的变量使用传统命名。

具体来说,它们在变量名前面加上了$符号,就像在 jQuery 中一样。这让他们或者未来的开发者知道变量中包含的是什么。让我们继续在我们的应用程序顶部添加这些定义。在读取// 变量定义放在这里后面的一行,添加以下行。它们分别指的是标题输入字段和笔记文本区域字段:

var $title = $('#title');
var $note = $('#note');

作为这个函数的最后一步,我们调用app.displayNotes()来更新笔记列表。由于该函数尚不存在,接下来我们来创建它。

构建显示笔记功能

在编写上一节时,你可能已经测试了添加笔记功能。这意味着你至少已经在localStorage中保存了一个笔记,用于测试显示笔记功能。到现在为止,你已经熟悉了我们在任何新节的第一步。继续添加你的空白displayNotes()函数来保存我们的代码:

app.displayNotes = function(){
}

接下来,我们需要从localStorage中检索所有的笔记:

// get notes
var notes = localStorage['Notekeeper'];
// convert notes from string to object
return JSON.parse(notes);

你可能会注意到我们的许多函数都有一个模式,几乎所有这些函数都以从 localStorage 中检索笔记开始。虽然只需要两行代码来执行此任务,但我们不需要在每次需要获取笔记时重复这两行代码。所以我们将编写一个包含这两行代码的快速辅助函数。它看起来类似于以下代码片段:

app.getNotes = function(){
// get notes
var notes = localStorage['Notekeeper'];
// convert notes from string to object
return JSON.parse(notes);
}

有了我们的新辅助函数,我们可以像下面的代码片段中所示,在 displayNotes() 函数中使用它:

app.displayNotes = function(){
// get notes
var notesObj = app.getNotes();
}

现在我们有了包含我们笔记数据的 notesObj 变量,我们需要循环遍历该数据包并输出内容:

// create an empty string to contain html
var html = '';
// loop over notes
for (n in notesObj) {
html += li.replace(/ID/g,n.replace(/-/g,' ')).replace(/LINK/g,n);
}
$ul.html(notesHdr + html).listview('refresh');

对于 for 循环内的一行具有多个替换语句可能看起来有些奇怪,但是 JavaScript 的性质允许方法链式调用。链式调用指的是返回其操作结果的整个结果的方法。添加额外的方法调用只是简单地重复该过程。

这个代码块中可能有一些新概念,所以让我们仔细看看。名为 html 的变量并不特别,但我们如何使用它可能是特别的。当我们遍历现有的笔记时,我们将新信息存储到 html 变量中,以及其他任何内容。我们通过使用 += 运算符来实现这一点,该运算符允许我们同时赋值和追加。

第二件你可能注意到的事情是赋值右边的 li。它从哪里来?那是一个尚未创建的单个列表项的模板。让我们在谈论它之前就做这件事。在你的 app.js 文件顶部,在读取 // 变量定义在此 之后的一行之后,添加以下两行代码:

var $ul = $('#notesList');
var li = '<li><a href="#pgNotesDetail?title=LINK">ID</a></li>';

你应该已经熟悉了在变量前加$来表示一个 jQuery 对象的约定。这就是我们在 $ul 变量中所做的事情。第二个变量,li 有些不同。它包含了一个单独的列表项的 HTML,用于显示一个笔记标题。最好的做法是尽可能避免在 JavaScript 中混合使用 HTML 或 CSS。我们现在将其声明为一个模板,以防将来决定在多个地方使用它。

另一个可能感兴趣的部分是我们如何使用 li 变量。在调用字符串替换函数时,我们正在查找单词 LINK 的所有出现,并用笔记的标题替换它。因为 JavaScript 是大小写敏感的语言,所以我们可以安全地假设我们不会遇到该单词的自然出现。

动态添加笔记到我们的列表视图

在我们的笔记显示在页面上之前,还有最后一件事情要安排。您可能已经注意到,唯一调用displayNotes()函数的地方出现在addNote()函数内部。这是一个很好的地方,但它不能是唯一的地方。我们需要在页面首次加载时运行某些内容。这个地方最好是在init()函数中,并且这就是我们要放置它的地方。

不过,有一个问题,我们不能只加载我们的笔记然后运行,如果没有笔记会发生什么?我们需要向用户显示一个友好的消息,以便他们不会认为出了什么问题。让我们创建一个名为app.checkForStorage()的新函数来处理所有这些:

app.checkForStorage = function(){
// are there existing notes?
if (localStorage['Notekeeper']) {
// yes there are. pass them off to be displayed
app.displayNotes();
} else {
// nope, just show the placeholder
$ul.html(notesHdr + noNotes).listview('refresh');
}
}

到现在为止,所有这些对你来说应该都很熟悉:检查localStorage是否有笔记,并在找到它们时调用displayNotes()函数。不过,第二部分有一些新内容。当我们为$uljQuery 对象设置 html 时,我们调用了两个新变量。一个是列表视图的标题,另一个是如果我们没有任何笔记时的情况。让我们现在添加这两个变量定义。在// 变量定义在此处下面,添加以下两行:

var notesHdr = '<li data-role="list-divider">Your Notes</li>';
var noNotes = '<li id="noNotes">You have no notes</li>';

行的最后一部分通常可能会被忽视,但我们不会让它被忽视。这真的很重要。jQuery Mobile 为开发人员提供了选择。一种选择是使用静态 HTML 代码,在页面加载时已经存在;jQuery Mobile 还提供了在运行时添加 HTML 代码的选项。这确实给开发人员带来了很大的灵活性,但同时也提出了一个独特的挑战。按设计,jQuery Mobile 在页面加载之前将 HTML 转换为时尚的按钮。这意味着在此之后添加的任何 HTML 将以没有任何样式的方式呈现给用户。

然而,jQuery Mobile 也提供了一种方法来解决这个问题,即内置刷新每个转换的元素的功能。大多数元素都有一个与元素名称对应的内置函数;在我们的情况下,它是listview()函数。实际上,这种方法提供了向页面添加一个全新列表视图的能力。在我们的情况下,我们只关心刷新我们已经拥有的列表视图,因此我们只需添加refresh关键字,jQuery Mobile 就会将你的纯文本列表视图转换。试着省略最后一部分,看看 jQuery Mobile 能为你节省多少工作量。也许你应该将 jQuery Mobile 团队加入你的圣诞卡列表?

最后,我们必须实际调用我们的最新函数。在init()函数中添加以下行。然后重新加载页面,看看你的笔记如何加载。

app.checkForStorage();

查看笔记

此时,我们应该能够创建一个新的笔记,并且该笔记会立即显示在我们的列表视图中。事实上,列表视图中的行已经是链接,它们只是不起作用,让我们立即更改它。

使用 Live 函数

将以下行添加到bindings()函数中:

$('#notesList a').live('click',function(e){
e.preventDefault();
var href = $(this)[0].href.match(/\?.*$/)[0];
var title = href.replace(/^\?title=/,'');
app.loadNote(title);
});

这个新的绑定有一些新概念,所以让我们来解析一下。首先,我们不使用 bind 函数,而是使用 jQuery 的 live函数。区别在于 bind 仅适用于现有的页面元素,而 live 是主动的。它既适用于现有元素,也适用于应用绑定后创建的元素。

绑定的第二行和第三行可能看起来有点混乱,但它们只做一件事。它们从被点击的链接的 href 属性中检索 URL。我们在本章前面定义的 li 模板包含每个列表项的以下 URL:

#pgNotesDetail?title=LINK

displayNote() 函数运行后,URL 看起来像这样(将鼠标悬停在每个列表项上,以查看其在浏览器窗口底部的链接):

#pgNotesDetail?title=the-title-of-the-note

最后,我们告诉我们的代码运行一个名为 app.loadNote() 的新函数。

动态创建一个新页面

如果你还没有为我们的新 loadNote() 函数创建一个新的空函数块,现在就去做吧。记住,我们要传入要查看的笔记的标题,所以确保在 loadNote() 函数中添加这个作为参数:

app.loadNote = function(title){
}

然后将以下两行放在函数的顶部:

// get notes
var notes = app.getNotes();
// lookup specific note
var note = notes[title];

第一行检索我们的笔记对象,而第二行提取用户请求的具体笔记。下一个变量定义打破了我们之前在本章提到的关于混合 HTML 和 JavaScript 的规则,但每个规则都有例外。我们在这里定义它,而不是在我们的 JS 文件的标题,因为它只在这里需要。这仍然可以保持文档的组织性。

var page = '<div data-role="page" data-url="details" data-add-back- btn="true">\
<div data-role="header">\
<h1>Notekeeper</h1>\
<a id="btnDelete" href ="" data-href="http://ID data-role="button" class="ui-btn-right">Delete</a>\
</div>\
<div data-role="content"><h3>TITLE</h3><p>NOTE</p></div>\
</div>';

page 变量现在包含了显示"笔记详情"页面所需的所有 HTML。你还记得我们的应用只有一个 HTML 文件吗?我们实际上正在使用先前的 HTML 代码从头开始创建整个页面。其中也有一些值得指出的细节:

  • 默认情况下 jQuery Mobile 不为页面提供返回按钮。然而,你可以在每个页面上使用 data-add-back-btn="true" 属性来启用返回按钮,该属性需要添加在带有 data-role="page" 属性的任何 div 标签上。

  • data-url 属性是 jQuery Mobile 使用的标识符,以便可以跟踪生成的多个页面。

现在我们在一个变量中包含了整个页面,我们可以对它做什么?我们可以将它转换为 jQuery 对象。通过用 $() 将任何独立的 HTML 块包装起来,我们就可以将其转换为一流的 jQuery 对象:

var newPage = $(page);

然后我们可以取出新创建页面的 HTML,并用我们选择的笔记的值替换部分内容。

//append it to the page container
newPage.html(function(index,old){
return old
.replace(/ID/g,title)
.replace(/TITLE/g,title
.replace(/-/g,' '))
.replace(/NOTE/g,note)
}).appendTo($.mobile.pageContainer);

从版本 1.4 开始,jQuery 提供了在某些函数内部使用回调的选项。这些函数包括.html().text().css()等几个。该函数期望两个参数,第二个参数包含当前匹配元素中包含的完整 HTML。这意味着我们可以对newPage变量内包含的 HTML 进行微调,而不必完全更改它。太棒了,不是吗?

接下来,我们将整个newPage变量追加到当前页面的末尾,这里通过$.mobile.pageContainer常量引用。最后,因为我们取消了绑定中的默认点击操作,所以我们必须告诉链接执行一个操作,即将用户转到这个新创建的页面。jQuery Mobile 提供了内置的方法来实现这一点:

$.mobile.changePage(newPage);

现在是大揭示的时刻。如果你在浏览器中加载notekeeper.html,你应该能够在一个浏览器窗口内添加、显示和最终查看笔记。jQuery Mobile 是不是很棒?

动态创建新页面

删除笔记

回顾我们应用程序的需求,我们做得相当不错。我们编写了设置文档结构的 HTML 代码,允许我们添加笔记、显示笔记和查看笔记。剩下的只是删除一个笔记,它始于我们在bindings()函数中设置的最后一个绑定。现在就让我们添加它:

$('#btnDelete').live('click',function(e){
e.preventDefault();
var key = $(this).data('href');
app.deleteNote(key);
});

在这个绑定中,可能有一个对你来说是新的项目,那就是 jQuery 的.data()函数的使用。HTML 5 允许你通过使用以data-为前缀的属性直接在任何 HTML 元素上存储任意数据,而这种能力是 jQuery Mobile 功能的核心。任何你看到data-role="something"的地方,你都在看 HTML 5 数据的作用。此外,jQuery 允许你通过使用.data()函数并传入你想查看的项目的键来检索任何data-值。在上面的情况中,我们将笔记的标题存储到了查看页面中的删除按钮上的data-href属性中。因为我们正在添加的绑定是一个分配给删除按钮的点击处理程序,所以我们可以通过调用$(this).data('href')来检索笔记的标题。太棒了!

这将是我们在本章中添加的最后一个函数。你难过吗?这确实是一个令人难忘的时刻,但是在你成为一名成功的 jQuery Mobile 开发人员之后,我们可以怀着美好的回忆回顾这一刻。再次,我们从一个接受单个参数,即我们要删除的笔记的标题的空函数开始。

app.deleteNote = function(key){
}

随后是我们用于检索笔记的辅助函数的函数定义:

// get the notes from localStorage
var notesObj = app.getNotes();

然后我们删除笔记。你已经在我们审阅localStorage时看到了它的作用,所以应该对你来说很熟悉:

// delete selected note
delete notesObj[key];
// write it back to localStorage
localStorage['Notekeeper'] = JSON.stringify(notesObj);

删除备注紧随其后的是将剩余备注重新写入localStoragedeleteNote()函数中的最后两行将我们带回到应用程序的主页面,即备注列表。它们还会触发原始的checkForStorage()函数。

// return to the list of notes
$.mobile.changePage('notekeeper.html');
// restart the storage check
app.checkForStorage();

最后一行可能对你来说有些奇怪,但请记住,我们事先不知道是否还有任何备注。运行存储检查允许我们显示占位文本,以防没有备注。养成这种习惯很好,因为它有助于减少我们的应用程序出现错误的可能性。

摘要

在本章中,我们使用 jQuery Mobile 构建了一个活生生的移动应用程序。停下来给自己一个赞。我们通过列出应用程序的要求、构建线框图和编写 HTML 的过程来完成了这一过程。我们学习了关于 HTML 5 的localStorage,使用模板进行文本替换,以及 jQuery Mobile 的一些更酷的功能,包括动态添加和刷新页面上的元素。

在下一章中,你将学习如何为 jQuery Mobile 设置全局配置选项,如何在 jQuery Mobile 中使用其他 API 来处理表单和内容块。

第十一章:增强 jQuery Mobile

在本章中,我们将学习如何增强 jQuery Mobile,如何通过创建主题和图标来改善应用程序的外观和功能,使您的移动应用程序真正脱颖而出。

在本章中,我们将:

  • 了解 jQuery Mobile 的构建模块

  • 使用 ThemeRoller 创建我们自己的 jQuery Mobile 主题

  • 为我们的应用设计并实现自定义图标

有什么可能?

当许多开发人员第一次使用 jQuery Mobile 时,他们的反应是对其易于实现丰富、引人入胜的移动网站感到敬畏。它轻松将普通 HTML 转换为美观、可用的按钮和列表视图。表单元素非常容易处理。jQuery Mobile 团队甚至随包提供了五种设计良好、吸引人的主题和 18 个常用图标。他们甚至建立了一个工具,供我们使用来构建自己的主题;ThemeRoller

在使用 jQuery Mobile 一段时间后,开发人员可能会问"我还可以用这个做什么别的吗?" 就像 60 年代和 70 年代的肌肉车一样。它们已经很棒了,但调整者和发烧友还想做更多。如果你有这种心态,那么本章就是为你准备的。

关于 jQuery Mobile 的美妙之处在于,因为它全部是普通的 CSS 和 HTML,我们几乎可以用很少的工作做任何我们想做的事情。在本章中,我们将使用 ThemeRoller 为 jQuery Mobile 从头开始创建自己的主题。我们将设计按钮并编写必要的 CSS 代码来实现低分辨率和高分辨率版本。我们还将探讨如何扩展 jQuery Mobile 中已有的样式和类,并制作出不同和独特的东西。那么,让我们开始吧?

jQuery Mobile 的视觉构建模块

正如你已经看到的,jQuery Mobile 非常用户友好且外观令人愉悦。它充分利用了圆角、微妙的渐变、投影来突出元素与周围环境的区别,以及其他技巧,这些技巧多年来一直是平面设计师在印刷品中使用的。但在网络上,这些效果只能通过使用图片或复杂且支持不佳的插件和小程序来实现。

随着 Web 2.0 和 CSS 3 的出现,所有这些选项都已提供给我们,即普通的网页开发人员。只需记住,权力越大,责任越大。jQuery Mobile 基于渐进增强的原则运作。这个繁琐的短语只是意味着您应该为理解这些增强的浏览器开发,并为理解它们的浏览器提供增强。

幸运的是,这些样式上的附加几乎纯粹是装饰性的。如果浏览器不理解border-radius声明,那么它将简单地显示方形边角。渐变和阴影也是如此。虽然 jQuery Mobile 默认为您的应用程序添加这些效果,但了解如何自己添加它们也是值得的。

圆角

圆角可以是最优雅和吸引人的效果之一,也是最简单的效果之一。开发人员需要了解此效果和其他效果的一些注意事项。虽然 W3C 推荐了border-radius的规范,但事实证明,每个主要浏览器制造商对其支持的方式略有不同。最终结果是相同的,但路径不同。让我们来看一下最基本的border-radius声明,以下屏幕截图是其结果:

#rounded {
border-radius: 10px;
}

圆角

您还可以选择仅使某些角变圆,以及调整值,使角不是完美的四分之一圆。让我们看几个更多的示例。以下代码片段和屏幕截图演示了一个示例,以获得两个圆角:

#topLeftBottomRight {
border-radius: 15px 0 15px 0;
}

圆角

以下代码片段和屏幕截图演示了一个示例,以获得一个圆角:

#bottomLeft {
border-top-left-radius: 100px 40px;
}

圆角

遗憾的是,目前情况并不像这么简单。因为每个浏览器供应商都对此效果有自己独特的渲染,像谷歌或 Mozilla 这样的软件开发者已经开始创建自己的版本,通常称为厂商前缀。为了使先前的样式声明具有最广泛的覆盖范围,您需要添加以下代码行:

#rounded {
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
}
#topLeftBottomRight {
-webkit-border-top-left-radius: 15px;
-webkit-border-bottom-right-radius: 15px;
-moz-border-radius-topleft: 15px;
-moz-border-radius-bottomright: 15px;
border-top-left-radius: 15px;
border-bottom-right-radius: 15px;
/* mozilla and webkit prefixes require you to define each corner individually when setting different values */
}
#bottomLeft {
-webkit-border-top-left-radius: 100px 40px;
-moz-border-radius-topleft: 100px 40px;
border-top-left-radius: 100px 40px;
}

应用投影阴影

CSS 中的投影阴影有两种形式:文本阴影(应用于文本)和框阴影(应用于其他所有内容)。与border-radius一样,如果您查看 W3C 规范,投影阴影也相对简单。

使用 text-shadow

让我们先看一下text-shadow

p {
text-shadow: 2px 2px 2px #000000;
/* horizontal, vertical, blur, color */
}

使用 text-shadow

该属性还通过在逗号分隔的列表中添加附加声明来支持多个阴影,如以下代码片段和输出所示:

p {
text-shadow: 0px 0 px 4px white,
0 px -5px 4px #ffff33,
2px -10px 6px #ffdd33,
-2px -15px 11px #ff8800,
2px -25px 18px #ff2200
}

使用 text-shadow

border-radius属性不同,text-shadow属性不需要厂商前缀。这并不意味着所有浏览器都支持它,这只是意味着支持此属性的浏览器会按预期显示,而不支持此属性的浏览器则会看不到任何内容。

使用 box-shadow

Box-shadow 遵循与 text-shadow 非常相似的模型,只是增加了一个关键词inset,允许内部阴影。让我们看一些示例。第一个示例显示了标准外部阴影:

#A {
-moz-box-shadow: -5px -5px #888888;
-webkit-box-shadow: -5px -5px #888888;
box-shadow: -5px -5px #888888; /* horizontal, vertical, color */
}
#B {
-moz-box-shadow: -5px -5px 5px #888888;
-webkit-box-shadow: -5px -5px 5px #888888;
box-shadow: -5px -5px 5px #888888;
/* horizontal, vertical, blur, color */
}
#C {
-moz-box-shadow: 0 0 5px 5px #888888;
-webkit-box-shadow: 0 0 5px 5px #888888;
box-shadow: 0 0 5px 5px #888888;
/* horizontal, vertical, blur, spread, color */
}

使用 box-shadow

现在,在以下示例中,看看这些内部阴影。很酷,对吧?

#D {
-moz-box-shadow: inset -5px -5px #888888;
-webkit-box-shadow: inset -5px -5px #888888;
box-shadow: inset -5px -5px #888;}
#E {
-moz-box-shadow: inset -5px -5px 5px #888888;
-webkit-box-shadow: inset -5px -5px 5px #888888;
box-shadow: inset 0px 0px 10px 20px #888888;
}
#F {
-moz-box-shadow: inset -5px -5px 0 5px #888888;
-webkit-box-shadow: inset -5px -5px 0 5px #888888;
box-shadow: inset 0 0 5px 5px #888888;
}

使用 box-shadow

值得一提的是,阴影和文本阴影都可以使用不常用的 rgbrgba 声明来设置它们的颜色。这使得开发者可以使用更熟悉的 RGB 值的约定来设置颜色。rgba 声明还允许设置颜色的不透明度从 01。修改的代码如下所示:

#opacity {
box-shadow: inset 0 0 5px 5px rgb(0,0,0); /* black */
}
#transparent {
box-shadow: inset 0 0 5px 5px rgba(0,0,0,.5);
/* black with 50% transparency */
}

CSS 渐变

CSS 渐变是向你的网站添加美感和冲击力的绝佳方式。选项包括线性渐变(从右到左,从上到下等等),以及径向渐变(从中心向外)。默认情况下,渐变由起始颜色和结束颜色组成。CSS 渐变也可以使用颜色停止来添加额外的色调。

然而,老版本浏览器对 CSS 渐变的支持并不完美,特别是在 Internet Explorer 中。好消息是,有办法解决 IE 的问题,可以让开发者可靠地在开发中使用渐变。坏消息是,支持该功能的代码非常复杂。让我们来看一下最简单的渐变声明:

div {
width: 500px;
height: 100px;
background: linear-gradient(left, #ffffff 0%,#000000 100%);
}

渐变声明可能相当复杂,所以让我们用一个信息图来分解它:

CSS 渐变

现在关键来了......在撰写本文时,没有浏览器支持使用实际属性的 W3C 规范。让我们来看一下支持多个浏览器的代码,你会更加喜欢 jQuery Mobile:

div {
width: 500px;
height: 100px;
border: 1px solid #000000;
/* Old browsers */
background: #ffffff;
/* FF3.6+ */
background: -moz-linear-gradient(left, #ffffff 0%, #000000 100%);
/* Chrome10+,Safari5.1+ */
background: -webkit-linear-gradient(left, #ffffff 0%,#000000 100%);
/* Opera 11.10+ */
background: -o-linear-gradient(left, #ffffff 0%,#000000 100%);
/* IE10+ */
background: -ms-linear-gradient(left, #ffffff 0%,#000000 100%);
/* W3C spec*/
background: linear-gradient(left, #ffffff 0%,#000000 100%);
/* IE6-9 */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#000000',GradientType=1 );
}

CSS 渐变

你可以通过添加额外的逗号分隔声明来将多种颜色添加到你的渐变中。例如,以下代码:

div {
width: 500px;
height: 100px;
border: 1px solid #000000;
/* Old browsers */
background: #ffffff;
/* FF3.6+ */
background: -moz-linear-gradient(left, #ffffff 0%, #000000 35%, #a8a8a8 100%);
/* Chrome10+,Safari5.1+ */
background: -webkit-linear-gradient(left, #ffffff 0%,#000000 35%,#a8a8a8 100%);
/* Opera 11.10+ */
background: -o-linear-gradient(left, #ffffff 0%,#000000 35%,#a8a8a8 100%);
/* IE10+ */
background: -ms-linear-gradient(left, #ffffff 0%,#000000 35%,#a8a8a8 100%);
/* W3C */
background: linear-gradient(left, #ffffff 0%,#000000 35%,#a8a8a8 100%);
/* IE6-9 */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#a8a8a8',GradientType=1 );
}

结果显示在以下渐变中:

CSS 渐变

正如你在阅读最近几页后可能猜到的那样,jQuery Mobile 为你做了很多繁重的工作。它不仅添加了漂亮的渐变页面背景,还必须跟踪可能阻止甜美的阴影出现的所有浏览器怪癖。当我们进入下一节时,你可能会对它处理主题和色板的方式更为印象深刻。

jQuery Mobile 主题的基础知识

在 jQuery Mobile 中进行主题设置对开发者来说是直接简单易用的,但是在幕后却相当复杂。幸运的是,很少有时候你需要知道为你所做的一切。然而,花点时间了解它的工作原理也是值得的。

jQuery Mobile 的开箱即用版本包含了一个由五种颜色色板组成的主题集,每个与 A-E 中的一个字母相关联。该主题包含了一系列基本的 CSS 类,可以随意应用于几乎任何元素,并且它们包含了宽度、高度、边框半径、阴影的全局设置。各个色板包含了有关颜色、字体等方面的具体信息。

可以将额外的样本添加到来自 F-Z 的五个原始样本中,或者可以随意替换或覆盖原始样本。这个系统允许共有 26 个不同的样本,从而可以产生数百万种主题颜色、样式和图案的可能组合。您可以通过添加一个data-theme属性和所需主题的字母来将 jQuery Mobile 主题应用于所选元素:

jQuery Mobile 主题的基础知识

开发人员通常会选择使用data-theme属性方法来应用样式,但也可以直接将 CSS 类名附加到页面元素以获得更精细的控制。有几个主要前缀允许这种灵活性。

条(.ui-bar-?)

bar 前缀通常应用于标题、页脚和其他重要区域:

条(.ui-bar-?)

内容块(.ui-body-?)

内容块通常应用于预期出现段落文本的区域。它的颜色有助于确保文本颜色与其放置在其上的文本颜色之间具有最大的可读性:

内容块(.ui-body-?)

按钮和列表视图(.ui-btn-?)

按钮和列表视图是 jQuery Mobile 库中最重要的两个元素,您可以放心地知道团队花了很多时间来完善它们。.ui-btn前缀还包括用于上升、下降、悬停和活动状态的样式:

按钮和列表视图(.ui-btn-?)

混搭样本

jQuery Mobile 中主题的一个好处是,除非另有说明,否则子元素会从其父元素继承。这意味着,如果您在页眉或页脚栏中放置一个没有自己data-theme属性的按钮,该按钮将使用与其父元素相同的主题。酷,对吧?

混搭样本

在一个元素中使用一个样本并在另一个元素的子元素中使用另一个样本也是完全可以接受甚至是鼓励的。这可以帮助元素更加突出,或者与应用程序的不同部分匹配,或者开发人员选择的任何其他原因。这是可能的,而且更重要的是,它很容易。只需将按钮(或其他元素)放置在页眉栏内,并为其分配自己的data-theme属性:

混搭样本

全站活动状态

jQuery Mobile 还为所有元素应用了一个全局 活动 状态。此活动状态用于按钮、表单元素、导航等任何需要指示当前选择的地方。更改此颜色值的唯一方法是通过 CSS 设置(或覆盖)它。活动状态的 CSS 类名是.ui-btn-active

全站活动状态

默认图标

jQuery Mobile 集中包含了 18 个图标,涵盖了开发人员广泛的需求。图标集是白色的透明图标,jQuery Mobile 在半透明的黑色圆圈上覆盖以提供与所有样品的对比度。要添加图标,请使用所需图标的名称指定 data-icon 属性:

默认图标

jQuery Mobile 还提供了使用 data-iconpos="[top, right, bottom, left]" 属性在按钮的顶部、右侧、底部或左侧放置图标的功能,其中左侧是默认位置。开发人员还可以通过指定 data-iconpos="notext" 来仅显示图标而不显示文本:

默认图标

部署自定义图标也是可能的,将在本章后面进行讨论。

创建和使用自定义主题

我们已经讨论过 jQuery Mobile 中主题设置的强大功能。它使得用简单而优雅的样式开发丰富的移动网站变得轻而易举。更强大的是,您可以创建自己的样品库,以使您的应用程序或网站真正独特。可以通过以下两种方式之一来处理自己的主题开发:

  1. 下载并打开现有的 jQuery Mobile CSS 文件,并按自己的意愿进行编辑。

  2. 将您的网络浏览器指向 jQuery Mobile 的 ThemeRoller:jquerymobile.com/themeroller/

我们将专注于第二种选择,因为说实话,为什么要费劲地浏览所有的 CSS 呢?您可以在 10 分钟内使用指点、点击和拖放的方式创建一个充满样品的新主题。让我们了解一下 ThemeRoller 是什么。

什么是 ThemeRoller?

ThemeRoller for jQuery Mobile 是为 jQuery UI 项目编写的一个基于 Web 的应用程序的扩展。它允许用户使用拖放颜色管理在几分钟内快速组装一个充满样品的主题。它具有交互式预览功能,因此您可以立即看到您的更改如何影响您的主题。它还具有内置的检查器工具,可帮助您深入了解细节(如果您需要)。它还集成了 Adobe® Kuler®,一个颜色管理工具。您可以在完成后下载您的主题,可以通过自定义 URL 与他人共享,也可以重新导入过去的主题进行最后的微调。它是一个强大的工具,是 jQuery Mobile 的完美补充。

五个默认样品的特点之一是,jQuery Mobile 团队花了相当多的时间来改善可读性和可用性。这些样品的对比度从最高(A)到最低(E)不等。在单个主题中,对比度最高的区域是页面上最突出的区域。这包括页眉(和列表视图的标题)和按钮。在创建自己的主题时,牢记这一点是个好主意。我们总是希望专注于应用程序的可用性,对吗?如果由于颜色选择不当而无法阅读,那么漂亮的应用有什么用呢?

使用 ThemeRoller

当你加载 ThemeRoller 时,第一件事就是看到一个看起来很漂亮的启动屏幕,然后是一个有用的入门屏幕:

使用 ThemeRoller

入门屏幕上有一些有用的提示,所以在点击开始按钮之前一定要看一眼:

使用 ThemeRoller

当所有的启动屏幕都结束后,你将会看到主要界面:

使用 ThemeRoller

ThemeRoller 分为四个主要区域:预览、颜色、检查员和工具。每个区域都包含了我们需要审查的重要功能。我们将从预览部分开始。

预览

除非你正在加载现有主题,否则预览区域将呈现三个完整、相同且交互式的 jQuery 移动页面,上面装满了各种小部件:

预览

将鼠标移到上面,你会发现每个页面都是功能性的。每个页面的页眉包含了一个字母,指示了哪个色板控制了它的外观。

颜色

在页面顶部,你会看到一系列颜色芯片,以及两个滑块控件和一个切换按钮。右边更远处,你会看到另外十个颜色芯片,应该是空白的。这些专门用于最近使用的颜色,直到你选择了颜色为止:

颜色

在颜色芯片下面有两个标有亮度饱和度的滑块。亮度滑块调整了一系列色板的明亮和暗色调,而饱和度使颜色更加鲜艳或柔和。综合在一起,用户应该能够近似于他们选择的任何颜色。要使用 Kuler®的颜色,点击标有Adobe Kuler 色板的文本链接。

每个颜色芯片都可以拖放到预览区域内的任何元素上。这使得色板集的开发非常容易。请注意,许多 jQuery Mobile 样式重叠,比如页顶的标题栏与列表视图的标题接收到相同的样式。根据需要调整颜色,然后将每个色片拖放到页面上的元素上。请记住,每个单独的页面都是自己的色板,所以在选择混合颜色时要小心。

检查员

界面最左侧是检查员面板,分为两部分。顶部包含了一系列按钮,允许开发者下载他们的主题,导入现有主题,并分享他们的主题链接。还有一个帮助链接给那些没有购买这本书的人:

检查员

底部区域包含一系列标有全局, A, B, C+的标签。每个标签都包含一个手风琴面板,其中包含了单个色板的所有值,除了全局标签,它适用于所有色板。

选择全局选项卡,然后点击活动状态,手风琴面板将展开,显示整个主题的活动状态设置。选项包括文本颜色、文本阴影、背景和边框。在全局更改值会导致每个当前(和将来的)色板都反映新的设置。

可以通过两种方式向主题添加额外的色板。点击检查器顶部的+选项卡会在你的主题中的最后位置添加一个新的色板。你也可以通过点击预览区域底部的添加色板按钮来添加一个新的色板。通过选择要删除的色板的选项卡,然后单击该色板名称右侧的删除链接来删除色板。请注意,从堆栈顶部删除色板会导致其余色板被重命名。

工具

页面顶部有一系列按钮。这些按钮允许你执行各种任务,我们马上就会介绍,但首先,仔细看看这些按钮本身:

工具

你会注意到以下按钮:一个切换按钮,允许你在当前 1.1 版本和 1.0.1 版本之间切换,撤销/重做,以及检查器的切换按钮。将此切换打开可以检查预览区域中的任何小部件。将鼠标悬停在小部件上会用蓝框突出显示该元素。单击该元素将导致检查器区域的手风琴菜单展开,显示特定于该元素的设置。

还有四个额外的按钮,允许你下载你的主题,导入或升级先前创建的主题,与他人分享你的主题,以及一个帮助按钮。

创建 Notekeeper 的主题

现在我们熟悉了 ThemeRoller 的界面,那么我们何不继续创建我们的第一个主题呢?与其在抽象中构建一个主题,不如创建一个我们实际将在之前构建的 Notekeeper 应用程序中使用的主题。让我们简单地开始,通过修改 jQuery Mobile 随附的现有主题之一。团队很友好地让用户导入默认主题作为新主题的起点,所以我们首先要去那里。点击窗口左上角的导入按钮,然后你会得到一个框,允许你粘贴现有主题的内容:

为 Notekeeper 创建主题

在右上角点击链接,适当命名为导入默认主题来导入默认主题。在文本区域填充 CSS 后,点击导入。预览区域将重新加载并显示从 AE 的色板。

我们将集中精力改变白色色板 D,因为它最接近我们的最终目标。由于我们更愿意使用色板 A 作为名称,让我们删除其他色板,以便只剩下 D。请记住,当你删除色板 A 时,ThemeRoller 会将其他色板重命名。这意味着当你删除色板 A 时,色板 B 变成 A,色板 C 变成 D,依此类推。

继续进行,直到原来是D的样本现在位于A位置。最后,删除样本 B(原来是样本 E),这样我们就只剩下样本 A:

为 Notekeeper 创建主题

这个样本看起来不错,但有点单调。让我们通过将页眉改为漂亮的绿色来注入一点色彩。确定任何元素的哪些值应该更改的最简单方法是使用检查器。在顶部切换检查器到On,然后点击主题 A 的页眉的任何地方。如果左侧选择了 A 选项卡,并且页眉/页脚栏面板展开,你就会知道你做对了:

为 Notekeeper 创建主题

你可以通过几种方式之一改变颜色。你可以直接将一个颜色芯片从顶部拖到背景上。你也可以将一个颜色芯片拖到输入字段上。最后,你可以手动输入值。注意,当你点击包含颜色值的字段时,你会看到一个时髦的颜色选择器。继续,并将此面板中的输入字段中的值更改为上一张截图中显示的值。

看起来不错,但现在主题活动状态的蓝色与我们的绿色不搭配。使用检查器工具,在 On/Off 切换栏的On部分单击一次。这将导致全局选项卡内的活动状态面板展开。我们将把蓝色改成一个漂亮的暖灰色。全局面板现在应该看起来类似于以下截图:

为 Notekeeper 创建主题

我们新主题唯一的不足之处是段落顶部的蓝色文本链接。回到我们可靠的检查器,让我们直接点击链接,这将展开内容主体面板,位于A选项卡内。现在,对于那些已经熟悉 CSS 的人来说,你知道你不能简单地改变链接颜色而不改变悬停状态,visited:hover 和活动状态。问题在于没有选项可以进行这些更改,但是 ThemeRoller 为你提供了解决方案。点击链接颜色输入字段右侧的+以显示其他选项,然后根据以下截图更改颜色:

为 Notekeeper 创建主题

就是这样。随时在探索检查器区域时进行其他主题的额外更改。无论你喜欢什么,都可以更改,现在只是位和字节而已。但请记住,目前没有撤销选项。如果你真的喜欢某些东西,请考虑写下值,以免丢失它们,或者将其导出为它是什么。说到…

导出你的主题

在我们实际导出主题之前,必须注意一件事。还记得带有“有用”信息的闪屏页面吗?事实证明,有一条不是建议,而是要求的。

我们建议用至少 3 个样本(A-C)来构建主题

为了使我们的主题正确应用到我们的 Notekeeper 应用程序中,我们需要将我们的单个色板(字母 A)复制到色板 BC 中。幸运的是,这是一件很容易的事情。在检查器顶部选择 A 选项卡,然后点击两次 + 选项卡。你应该会看到三个相同的色板,现在我们完成了。

现在我们已经完成了我们的主题,我们将导出它以在我们的 Notekeeper 应用中使用。这是一个简单的过程,从页面中间顶部的下载主题按钮开始。你将看到一个框,允许你为主题命名,一些关于如何应用主题的信息,以及一个标记为下载 Zip的按钮。在将我们的主题命名为 Notekeeper 后,点击下载 Zip按钮,你将在下载文件夹中收到一个美味的小东西。

解压缩 ZIP 文件的内容,你将看到以下的目录结构:

  • index.html

  • themes/

    • Notekeeper.css(你的主题的未压缩版本)

    • Notekeeper.min.css(压缩版本。在生产中使用此版本)

    • images/

      • ajax-loader.gif

      • icons-18-black.png

      • icons-18-white.png

      • icons-36-black.png

      • icons-36-white.png

树顶部的 HTML 文件包含了如何实现你的主题的信息,以及一些小部件来确认主题是否有效。示例文件中的所有链接都是相对的,因此你应该能够将其拖放到任何浏览器窗口中并查看结果。

关于主题的下载和实施的一些注意事项:

  1. jQuery 团队之所以向你提供此 ZIP 文件中的按钮图标是有原因的。主题要求这些图像与 CSS 文件相关联。这意味着,除非你已经在使用默认主题,否则在将你的主题上传到网站时,你还需要包含图像文件夹,否则图标将不会显示出来。

  2. 牢记你的主题的未压缩版本。虽然由于体积原因你不希望在生产中使用它,但是如果你希望在 ThemeRoller 中编辑它,你将需要它。截止到撰写本文时,ThemeRoller 无法导入被压缩的 CSS 文件。

创建和使用自定义图标

我们已经看到了使用 ThemeRoller 向 jQuery Mobile 添加自己的主题是多么简单。现在我们将通过创建一个自定义图标为我们的 Notekeeper 应用增添一些趣味。本节中的说明将专门针对 Photoshop,但任何能够导出透明 PNG 文件的图形应用程序都应该是可以接受的。

CSS 精灵

在我们创建和使用图标之前,我们应该先了解 jQuery Mobile 如何使用图标并应用它们。在你刚刚创建的主题中有几个图像文件(themes/images)。打开 icons-18-black.pngicons-36-black.png,在你选择的图形编辑器中将它们放大到 400% 或更多,你应该会看到与以下图像非常相似的东西:

CSS 精灵

当打开这些文件时,你可能会注意到每个图像都包含所有图标。这是因为 jQuery Mobile 利用了一种称为 CSS 雪碧图 的技术,它本身利用了 CSS 允许开发人员通过指定其容器内的位置来 裁剪 背景图像的事实,并隐藏通常显示在该容器外部的背景的任何其他部分。它的主要优点包括以下几点:

  1. 减少浏览器发出的请求数量。请求越少,通常意味着页面加载速度会更快。

  2. 图片位置居中。所有图标都可以在一个位置找到。

以下截图是该技术的简单说明:

CSS 雪碧图

浏览器始终从图像的左上角引用图像。在 CSS 语言中,即 0,0。要实现此效果,您将背景图像设置在一个容器上,然后简单地调整 XY 坐标,直到图像的位置与您的设计匹配。然后设置容器的溢出以裁剪或隐藏图像的其余部分。请记住,您正在 移动 图像到左侧,因此对于 X 位置,您将使用负数。使用前面的示例作为参考,以下代码片段用于实现此效果:

<html>
<head>
<title></title>
<style>
div {
background: url("icons-36-black.png");
background-position: -929px 4px;
background-repeat: no-repeat;
border: 1px solid #000000;
height: 44px;
overflow: hidden;
width: 44px;
}
</style>
</head>
<body>
<div></div>
</body>
</html>

设计你的第一个图标

我们只会创建一个单一图标,所以我们不需要图标周围的所有空白空间。让我们先决定我们想要描绘什么。我们的应用叫做 Notekeeper,它创建笔记。也许一个描绘纸张的图标会起作用?这样做的额外好处是在小尺寸下相对容易表示。在你选择的图像编辑器中创建一个新文档,尺寸为 36x36 像素,分辨率为 72 dpi。将其命名为 notekeeper-icon-black-36.png

设计你的第一个图标

尽管文档的尺寸是 36x36 像素,但图标的有效区域只有 22x22 像素。这是为了与 jQuery Mobile 团队提供的图标保持一致,以确保我们的图标看起来不奇怪。为了更容易地保持在线条内,使用矩形选择工具在 22px 处绘制一个正方形,然后将其位置设置在文档的顶部边缘和左侧边缘各 7px 处。

接下来,沿着每条边绘制指南线,使得你的文档看起来类似以下截图:

设计你的第一个图标

在绘制图标时,你需要考虑所描绘事物的尺寸和属性。你不可能表现出所有细节,但你需要传达事物的精神。一张纸比它宽高比更高,并且上面有线条。让我们从这两点开始,看看我们能得出什么。此套图标中的其他图标都有较粗的感觉,以便它们能在背景中显眼。让我们填充一个实心形状,然后删除页面的线条,以便图标具有相同的粗糙感。我们将用黑色绘制线条,以便它们在书中更好地打印出来,但我们的图标需要是白色的。确保你相应调整你的设计:

设计你的第一个图标

这个图标似乎符合我们所有的标准。它比宽高比更高,并且像纸一样有线条。它还有一个活泼的小翻页,给它一些态度。这不就是每个人在他们的纸图标上寻找的东西吗?确保图标的线条是白色的,然后保存它。jQuery Mobile 图标已保存为透明的 PNG-8 文件。这类似于 GIF 格式,但不是必需的。如果你愿意,可以使用透明 GIF 或透明 PNG-24。

当我们创建第一个图标时,我们创建了高分辨率版本。 为了简洁起见,我们将快速浏览创建低分辨率图标的步骤:

  1. 创建一个新的图像文档,尺寸为 18x18 像素。将其命名为notekeeper-icon-18

  2. 这个图标的活动区域将是 12x12 像素。绘制一个 12px 的正方形选择区域,然后将其位置设置为距离顶部 3px,距离左侧 3px。

  3. 绘制你的辅助线,然后草图出图标,使用以前的版本作为参考。在这么小的空间里画图标确实很难,不是吗?

  4. 你的最终结果应该类似于以下截图:设计你的第一个图标

将两个图像与你的 Notekeeper 主题一起保存并关闭 Photoshop。

高分辨率和低分辨率

分辨率是可以显示在给定区域内的点数或像素数。来自网络世界的你们通常将所有东西都以 72dpi 进行测量,因为大多数显示器都显示这个分辨率。如果你有很多移动设备的经验,你可能知道每个设备的分辨率可能与其旁边的设备不同。这样做的问题在于,分辨率更高的设备在屏幕上只是显示更多的像素。这意味着在高分辨率屏幕上显示的图像将比在低分辨率屏幕上显示的同一图像要小。

jQuery Mobile 通过为高分辨率和低分辨率设备提供两个版本的每个图标以及两套代码来解决此问题。在下一节中,我们将为我们的 Notekeeper 应用程序应用自定义主题和自定义图标。

更新 Notekeeper 应用程序

是时候将所有这些松散的端点联系在一起了。我们有一个使用 ThemeRoller 构建的自定义主题,我们有我们漂亮的自定义图标,现在是时候将所有的片段组合在一起了。您需要以下内容来完成:

  1. 你在 Notekeeper 章节末尾完成的代码。

  2. 您在本章前面创建的自定义主题。

  3. 您的自定义图标;白色;分别为 18px 和 36px 尺寸。

添加我们的自定义主题

让我们从最简单的部分开始。添加我们的自定义主题非常简单。打开notekeeper.html(在您的浏览器中,并在您选择的文本编辑器中)。查找<head>标签并添加以下行:

<title>Notekeeper</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/ latest/jquery.mobile.min.css" />
<link rel="stylesheet" href ="themes/Notekeeper.min.css" />
<link rel="stylesheet" href ="styles.css" />
<script src="img/jquery-1.6.4.js"></script>
<script src="img/jquery.mobile.min.js"></script>
<script src="img/application.js"></script>

第一行新加入了我们创建的新主题。第二行目前指向一个缺失的文件(因为我们还没有创建它)。即使像 jQuery Mobile 这样拥有丰富主题系统的系统,我们仍然会为各种事物编写一些自定义 CSS。styles.css是我们将放置各种样式的地方,特别是我们自定义图标的定义。

顺便说一句,您可以重新加载浏览器窗口,看看我们的新主题是如何运行的。是不是很漂亮?当我们的自定义图标出现时,它会看起来更加漂亮。

添加我们的自定义图标

接着,在你的 Notekeeper 应用代码的根目录下创建styles.css,然后打开它。我们将首先添加我们的 18px 图标的声明。它是低分辨率的,将在您的桌面浏览器中看到。高分辨率图标目前只在 iPhone 4 和 iPhone 4S 上显示。

要添加我们的自定义图标,我们遵循 jQuery Mobile 设定的模式。它使用.ui-icon前缀为按钮和其他元素应用图标。这意味着为了使我们的图标在框架中起作用,我们必须将我们的 CSS 类命名为以下内容:

.ui-icon-notekeeper-note {
background-image: url("themes/images/notekeeper-icon-white-18.png");
}

然后,将图标添加到我们的“添加笔记”按钮中就像添加一个data-icon属性一样简单,如下所示的代码行所示:

<div class="ui-block-b">
<input id="btnAddNote" type="button" value="Add Note" data- icon="notekeeper-note" />
</div>

请记住,字符串notekeeper-note可以是任何东西,只要它与您之前创建的 CSS 类的后半部分匹配即可。最后让我们为我们的应用程序添加剩下的一部分,即高分辨率图标。

jQuery Mobile 的一个显著特点是它对媒体查询的支持。媒体查询本质上允许您查询给定设备的各种信息,基于其媒体类型:屏幕、打印、电视、手持设备等。对这个查询的回答允许开发人员对 CSS 代码进行分支,并为桌面浏览器(屏幕)显示页面的一种方式,为电视(电视)显示页面的另一种方式。对于我们的图标,我们想要询问任何视图设备,其类型为屏幕,是否支持一个名为-webkit-min-device-pixel-ratio的属性,以及该属性的值是否为2。在低分辨率图标的声明之后,将以下行添加到styles.css中:

@media only screen and (-webkit-min-device-pixel-ratio: 2) {
.ui-icon-notekeeper-note {
background-image: url("themes/images/notekeeper-icon-white-36.png");
background-size: 18px 18px;
}
}

除了媒体查询代码之外,这个唯一与众不同的是background-size属性。它允许开发人员指定给定背景应按指定大小(18x18 像素)缩放,而不是其原始大小 36x36 像素。由于 iPhone 4 和 4S 上的分辨率恰好是低分辨率设备的两倍,这意味着我们将两倍的像素打包到与较小图标相同的空间中。最终结果是图标看起来更加清晰和锐利。如果您拥有其中一款设备,请将您的代码上传到服务器并查看它。您的耐心将会得到回报。

总结

在本章中,我们学习了对于 jQuery Mobile 体验至关重要的高级 CSS 技术,以及 jQuery Mobile 如何利用它们为最终用户提供丰富的界面。我们深入探讨了 jQuery Mobile 主题化的基础知识以及它的工作原理。我们使用 ThemeRoller 工具构建了一个自定义主题,用我们自己的双手创建了一个自定义图标,并学习了如何将所有这些东西联系在一起并在我们的应用程序中实现它们。

在下一章中,您将学习如何运用过去 11 章学到的原则,并创建一个可以在 iOS 和 Android 平台上运行的本机应用程序(以及其他几个平台),使用 Phonegap 开源库。

第十二章:创建原生应用程序

在本章中,我们将看看如何将基于 jQuery Mobile 的 Web 应用程序转化为移动设备的原生应用程序。我们将讨论 PhoneGap 框架以及它如何允许您利用设备的硬件。

在本章中,我们将:

  • 讨论 PhoneGap 项目及其功能

  • 演示如何使用 PhoneGap 的构建服务来创建原生应用程序

HTML 作为原生应用

对大多数人来说,在诸如 Android 或 iOS 之类的平台上创建原生应用程序需要学习全新的编程语言。虽然学习新语言并扩展技能的范围总是很好,但如果您可以利用现有的 HTML 技能并在移动设备上本地使用它们,那岂不是很酷?

幸运的是,正好有这样一个平台。PhoneGap (www.phonegap.com)是一个开源项目,允许您使用 HTML 页面创建原生应用程序。这段代码完全免费,可用于开发 iOS(iPhone 和 iPad)、Android(手机和平板电脑)、Blackberry、WebOS、Windows Phone 7、Symbian 和 Bada 的应用程序。PhoneGap 通过在原生环境中创建一个项目并指向一个 HTML 文件来工作。一旦设置好,您可以利用现有的 HTML、CSS 和 JavaScript 技能来创建应用程序的用户界面和功能。

更好的是,PhoneGap 还为您的 JavaScript 代码提供了额外的 API。这些 API 允许:

  • 加速器:允许您的代码检测设备上的基本运动

  • 摄像头:允许您的代码与相机配合使用

  • Compass:让您访问设备上的指南针

  • 联系人:提供基本的搜索和联系人创建支持

  • 文件:读/写访问设备存储

  • 地理定位:提供一种检测设备位置的方式

  • 媒体:允许基本的视频/音频捕获支持

  • 网络:确定设备的网络连接设置

  • 通知:创建通知的简单方式(通过弹出窗口、声音或振动)

  • 存储:访问一个简单的 SQL 数据库

通过使用这些 API,您可以将普通的 HTML 网站转化为功能强大的类原生应用程序,用户可以下载并安装到他们的设备上。

在我们继续之前,让我们简要了解一下PhoneGap。PhoneGap 是 Apache 目前处于孵化状态的开源项目。它已更名为Cordova。你可能会听到人们用这两个名字来指代它。在写这本书的时候,大多数人仍然把这个项目称为 PhoneGap,这也是我们将使用的术语。重要的是要记住,PhoneGap 是免费且开源的!

在我们继续之前,让我们快速讨论一下 PhoneGap 应用程序与原生应用程序的比较。在大多数情况下,原生应用程序的性能比使用 PhoneGap 创建的应用程序要快。PhoneGap 并不意味着取代原生开发。但通过允许您使用现有技能并一次部署到多个平台,其好处可能远远超过对性能的任何关注。

使用 PhoneGap

创建一个 PhoneGap 项目有两种主要方法。人们使用 PhoneGap 的主要方式是首先使用他们正在为之构建的平台的开发工具。所以,对于一个安卓项目,这涉及使用具有正确插件的 Eclipse 编辑器,而在 iOS 上则涉及使用 XCode。入门指南 (www.phonegap.com/start) 提供了如何为您选择的设备平台设置环境的详细信息:

使用 PhoneGap

对于每个平台的设置细节对于本书来说太多了(而且只是重复了 PhoneGap 网站上的内容),所以我们将专注于创建原生应用的另一种选项,即 PhoneGap Build 服务。PhoneGap Build (build.phonegap.com) 是一个在线服务,简化并自动化了创建原生应用的过程。它允许您简单地上传代码(或使用公共源代码控制存储库)以生成原生二进制文件。更好的是,您可以使用 PhoneGap Build 为所有受支持的平台生成二进制文件。这意味着您可以编写您的代码,并从该网站生成 iPhone、安卓、黑莓和其他版本的代码:

使用 PhoneGap

PhoneGap Build 服务并不免费。定价计划和其他详情可以在该网站上找到,但幸运的是有一个免费的开发者计划。这就是我们将在本章中使用的服务。让我们开始创建一个账户。(在接下来的屏幕截图和示例中,请确保将细节更改为您自己的特定内容。)

首先点击 创建账户 按钮并填写相关细节:

使用 PhoneGap

注册后,您将返回到 PhoneGap Build 的首页,您不会看到任何类型的确认消息。这有点不幸,但如果您检查您的电子邮件,您应该会看到他们发来的一封验证注册的消息。点击那个链接,您将被带到一个页面,询问您要创建您的第一个 PhoneGap Build 项目:

使用 PhoneGap

请注意,构建服务支持从新的 Github 存储库、现有的 Git 或 Subversion 存储库或通过上传的 ZIP 或 HTML 文件中的项目种子。此时,让我们离开网站,再回到代码。我们想要从一个非常简单的代码集开始。稍后在本章中我们会做一些更有趣的事情,但现在,我们的目标只是上传一些 HTML 并看看接下来会发生什么。在你从 GitHub 下载的代码中,打开c12文件夹,看看app1文件夹。其中包含了第四章 Working with Lists中一个列表示例的副本。它使用 jQuery Mobile 创建了一个简单的包括缩略图片的四人列表。这并不是太令人兴奋,但对我们目前的目的来说已经足够了。你会注意到已经有一个app1.zip文件。

如果你回到网站并选择上传存档,然后可以浏览到你从计算机上解压文件的位置并选择那个 ZIP 文件。确保还为应用程序输入一个名称。我选择了FirstBuildApp。点击创建后,你会被带到包含您所有应用程序的页面,如果您是一个新的构建用户,那里将只包含刚刚创建的一个应用程序。

使用 PhoneGap

点击应用程序标题,然后您可以选择下载各种版本的应用程序。信不信由你——你已经能够在大多数平台上下载版本。但使用 iOS 需要你提供额外的细节:

使用 PhoneGap

如果你看不到下载链接而是看到一个排队通知,请给构建服务一两分钟来赶上。如果你简单地重新加载页面,最终你就会看到链接显示出来。

真正使用应用程序取决于你选择的平台。对于安卓,你需要确保已启用允许安装非市场应用程序设置。该设置的确切措辞和位置将取决于您的设备。这个短语可以在我的 HTC Inspire 设备的应用设置中找到。您可以通过在 PhoneGap Build 网站上编辑设置来对应用程序签名。一旦你做过了,你就可以将你的应用程序提交到安卓市场。但由于安卓允许您测试时使用未签名的应用程序,您可以跳过此步骤。如果您下载 APK(表示您的应用程序的实际文件),您可以以几种方式将其放在设备上。安卓 SDK 包括从命令行安装应用程序的工具。最简单的方法是使用你的电子邮件。如果你将文件发给自己,并在设备上检查你的电子邮件,你应该能够在那里安装它。以下屏幕截图显示了我的手机上运行的应用程序:

使用 PhoneGap

添加 PhoneGap 功能

我们刚刚演示了如何使用 PhoneGap Build 服务将 HTML(当然还包括 JavaScript、CSS 和图像)转换为真正的本机应用程序,以适应多个平台。然而,在本章的前面部分提到过,PhoneGap 提供的不仅仅是简单的包装器来将 HTML 转换为本机应用程序。PhoneGap JavaScript API 提供了对许多酷炫的设备中心服务的访问,这些服务可以极大地增强您的应用程序的功能。对于我们的第二个示例,我们将看一下其中一个功能——联系人 API(有关详细信息,请参阅联系人 API 文档,可在docs.phonegap.com/en/1.4.1/phonegap_contacts_contacts.md.html#Contacts)上找到)。

应用程序在Listing 12-1中是一个简单的联系人搜索工具。让我们看看代码,然后解释一下其中的内容:

Listing 12-1: index.html
<!DOCTYPE html>
<html>
<head>
<title>Contact Search</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href ="jquery.mobile.min.css" />
<script src="img/jquery.js"></script>
<script src="img/jquery.mobile.min.js"></script>
<script src="img/phonegap-1.4.1.js"></script>
<script>
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady(){
$("#searchButton").bind("touchend", function() {
var search = $.trim($("#search").val());
if(search == "") return;
var opt = new ContactFindOptions();
opt.filter = search;
opt.multiple = true;
navigator.contacts.find(["displayName","emails"], foundContacts, errorContacts, opt);
});
foundContacts = function(matches){
//create results in our list
var s = "";
for (var i = 0; i < matches.length; i++) {
s += "<li>"+matches[i].displayName+"</li>";
}
$("#results").html(s);
$("#results").listview("refresh");
}
errorContacts = function(err){
navigator.notification.alert("Sorry, we had a problem and gave up.", function() {});
}
}
</script>
</head>
<body>
<div data-role="page">
<div data-role="header">
<h1>Contact Search</h1>
</div>
<div data-role="content">
<input type="text" id="search" value="adam" />
<button id="searchButton">Search</button>
<ul id="results" data-role="listview" data-inset="true"></ul>
</div>
</div>
</div>
</body>
</html>

让我们首先看看应用程序的布局部分,它位于文件的下半部分。您可以看到我们的 jQuery Mobile 页面结构,其中包括一个输入字段、一个按钮和一个空列表。这里的想法是用户将输入要搜索的名称,点击按钮,结果将显示在列表中。以下屏幕截图展示了输出:

添加 PhoneGap 功能

现在看一下 JavaScript 代码。我们所做的第一个更改是包含 PhoneGap JavaScript 库:

<script src="img/phonegap-1.4.1.js"></script>

此 JavaScript 库可从您从 PhoneGap 下载的 ZIP 文件中获得。即使我们不打算在本地构建我们的应用程序(当然您也可以),我们也需要在发送到 Build 服务的 ZIP 文件中包含 JavaScript 文件。这里有一个棘手的部分。截至 PhoneGap v 1.4.1,每个平台的 JavaScript 文件都是唯一的。这意味着 PhoneGap 支持的每个操作系统都有一个不同的 JavaScript 文件。Build 服务足够智能,可以用适当平台的正确文件替换您的文件引用。如果您使用本书的 Github 存储库中的代码,则是 Android 版本。如果您想将此代码用于 iOS,请务必在本地替换 JavaScript 文件。

下一个有趣的细节是以下代码行:

document.addEventListener("deviceready", onDeviceReady, false);

deviceready事件是由 PhoneGap 触发的特殊事件。它基本上意味着您的代码现在可以使用高级功能,例如 Contacts API。

在事件处理程序onDeviceReady中,我们有一些事情要做。值得注意的第一个函数是搜索按钮的事件处理程序。前几行代码只是获取、修整和验证值。

在确保实际有内容可以搜索后,您可以看到对 Contacts API 的第一个实际使用,如下面的代码片段所示:

var opt = new ContactFindOptions();
opt.filter = search;
opt.multiple = true;
navigator.contacts.find(["displayName","emails"], foundContacts, errorContacts, opt);

联系人 API 具有搜索方法。其第一个参数是要搜索和返回的字段数组。在我们的案例中,我们表示我们要针对联系人的姓名和电子邮件值进行搜索。第二个和第三个参数是成功和错误回调。最后一个选项是搜索的选项集。你可以在调用之前看到它被创建。过滤器键仅是搜索词条。默认情况下,联系人搜索返回一个结果,所以我们特别要求多个结果。

现在让我们来看一下成功处理程序:

foundContacts = function(matches){
//create results in our list
var s = "";
for (var i = 0; i < matches.length; i++) {
s += "<li>"+matches[i].displayName+"</li>";
}
$("#results").html(s);
$("#results").listview("refresh");
}

联系人搜索的结果将是一个结果数组。记住你只会得到你要求的内容,所以我们的结果对象包含 displayNameemails 属性。目前,我们的代码只是获取 displayName 并将其添加到列表中。根据我们从之前的章节学到的知识,我们还知道每当修改列表时,我们需要刷新 jQuery Mobile listview。以下屏幕截图显示了一个示例搜索:

添加 PhoneGap 功能

摘要

在本章中,我们研究了 PhoneGap 开源项目以及它如何允许你使用 HTML、JavaScript 和 CSS 创建多种不同设备的原生应用程序。我们使用 Build 服务并用它来上传我们的代码和下载编译后的原生应用程序。虽然 jQuery Mobile 不是 PhoneGap 的必需品,但两者组合在一起非常强大。

在下一章中,我们将使用这个团队创建我们的最终应用程序,一个功能齐全的 RSS 阅读器。

第十三章:成为专家 - 构建一个 RSS 阅读器应用程序

现在您已经了解了 jQuery Mobile 及其功能,是时候构建我们最终的完整应用程序了 —— 一个 RSS 阅读器。

在这一章中,我们将:

  • 讨论 RSS 阅读器应用程序及其功能

  • 创建应用程序

  • 讨论可以添加到应用程序的内容

RSS 阅读器 —— 应用程序

在深入代码之前,可能有必要快速展示应用程序的最终工作形式,以便您可以看到各个部分及其如何一起工作。RSS 阅读器应用程序就是这样一个应用程序,它旨在获取 RSS 源(例如来自 CNN、ESPN 和其他网站的源),将它们解析为可读数据,并提供一种查看文章的方式。该应用程序将允许您添加和删除源,提供名称和 URL,并提供一种查看源当前条目的方法。

应用程序始于一组基本说明。只有在您运行应用程序而没有任何已知源时才会显示这些说明:

RSS 阅读器 — 应用程序

单击 添加源 按钮会带您进入一个简单的表单,允许输入名称和 URL。(不幸的是,URL 必须手动输入。幸运的是,现代移动设备支持复制和粘贴。我强烈建议使用这个!):

RSS 阅读器 — 应用程序

添加源后,您将返回到主页。以下截图显示添加了一些源后的视图:

RSS 阅读器 — 应用程序

要开始阅读条目,用户只需选择其中一个源。然后,它将获取该源并显示当前的条目:

RSS 阅读器 — 应用程序

应用程序的最后部分是入口视图本身。有些博客不会通过 RSS 提供“完整”的入口副本,显然您可能希望在博客本身发表评论。因此,在底部我们提供了一种简单的方法来访问真正的网站,如下图所示:

RSS 阅读器 — 应用程序

现在您已经看到了应用程序,让我们来构建它。我们将再次使用 PhoneGap Build 来创建最终结果,但这个应用程序实际上也可以在常规网站上运行。(我们将稍后讨论为什么。)

创建 RSS 阅读器应用程序

我们的应用程序从第一个页面 index.html 开始。此页面将加载 jQuery 和 jQuery Mobile。它的核心任务是列出您当前的源,但它必须在用户没有任何源时识别出来,并提供一些文本鼓励他们添加他们的第一个源:

Listing 13-1: index.html
<!DOCTYPE html>
<html>
<head>
<title>RSS Reader App</title>
<meta name="viewport" content="width=device-width, initial- scale=1">
<link rel="stylesheet" href ="jquery.mobile/jquery.mobile- 1.1.0.min.css" />
<script src="img/jquery-1.6.4.min.js"></script>
<script src="img/jquery.mobile-1.1.0.min.js"></script>
<script src="img/main.js"></script>
</head>
<body>
<div data-role="page" id="intropage">
<div data-role="header">
<h1>RSS Reader Application</h1>
</div>
<div data-role="content" id="introContent">
<p id="introContentNoFeeds" style="display:none">
Welcome to the RSS Reader Application. You do not currently have any RSS Feeds. Please use the "Add Feed" button below to begin.
</p>
<ul id="feedList" data-role="listview" data-inset="true" data- split-icon="delete"></ul>
<a href ="addfeed.html" data-role="button" data-theme="b">Add Feed</a>
</div>
<div data-role="footer">
<h4>Created with jQuery Mobile</h4>
</div>
</div>
<script>
$("#intropage").bind("pagecreate", function(e) {
init();
});
</script>
</body>
</html>

如代码清单前所述,我们需要首先加载 jQuery 和 jQuery Mobile 模板。您可以在前面的代码清单的开头看到这一点。页面的大部分是您在上一章中看到的模板 HTML,所以让我们指出一些具体的内容。

首先注意下导语段落。注意 CSS 来隐藏文本吗?这里的假设是 — 大多数情况下 — 用户不会需要这段文字,因为他们会有订阅源。我们的代码将在必要时处理显示它。

在该段落之后是一个空列表,将显示我们的 feeds。在下面是用于添加新 feeds 的按钮。

最后,我们在最后放了一小段脚本。这创建了一个 jQuery Mobile 页面事件 pagecreate 的事件监听器,我们将它与启动我们的应用程序任务相关联。

我们所有的代码(我们的自定义代码)都将存储在 main.js 中。这个文件有点大,所以我们只显示与每个部分相关的部分。在阅读本章时,请记住这一点。整个文件可以在书中的示例代码中找到:

Listing 13-2: Portion of main.js
function init() {
//handle getting and displaying the intro or feeds
$("#intropage").live("pageshow",function(e) {
displayFeeds();
});

我们从 main.js 中的 init 函数开始。记住这个函数在首页的 pagecreate 上运行。它在页面显示之前运行。这使得它成为一个很好的地方去注册一个函数,用于页面显示时。我们已经将大部分逻辑提取到自己的函数中,所以接下来让我们来看看它。

displayFeeds 函数

displayFeeds 处理检索我们的 feeds 并显示它们。逻辑很简单。如果没有 feeds,我们想要显示导语文本:

Listing 13-3: displayFeeds from main.js
function displayFeeds() {
var feeds = getFeeds();
if(feeds.length == 0) {
//in case we had one form before...
$("#feedList").html("");
$("#introContentNoFeeds").show();
} else {
$("#introContentNoFeeds").hide();
var s = "";
for(var i=0; i<feeds.length; i++) {
s+= "<li><a href ='http://feed.html?id="+i+"' data- feed='"+i+"'>"+feeds[i].name+"</a> <a href ='http:// class='deleteFeed' data-feedid='"+i+"'>Delete</a></li>";
}
$("#feedList").html(s);
$("#feedList").listview("refresh");
}
}

注意我们还清空了列表。可能用户有 feeds 并删除了它们。通过将列表重置为空字符串,我们确保我们不留下任何东西。如果有 feeds,我们动态创建列表,确保在最后调用 listview("refresh") API,请求 jQuery Mobile 对列表进行美化。

存储我们的 feeds

那 feeds 是从哪里来的?我们如何存储它们?虽然我们正在使用 PhoneGap 并且可以使用嵌入式 SQLite 数据库实现,但我们可以使用更简单的东西 localStoragelocalStorage 是一个 HTML5 功能,允许你在客户端存储键值对。虽然你不能存储复杂的数据,但你可以在存储之前使用 JSON 序列化来编码复杂的数据。这使得数据的存储非常简单。但请记住 localStorage 包含文件存储。当数据发生变化时,您的应用程序需要从文件中读取。尽管我们谈论的是一个简单的 feed 列表,但这些数据应该相对较小:

Listing 13-3: getFeeds, addFeed, and removeFeed
function getFeeds() {
if(localStorage["feeds"]) {
return JSON.parse(localStorage["feeds"]);
} else return [];
}
function addFeed(name,url) {
var feeds = getFeeds();
feeds.push({name:name,url:url});
localStorage["feeds"] = JSON.stringify(feeds);
}
function removeFeed(id) {
var feeds = getFeeds();
feeds.splice(id, 1);
localStorage["feeds"] = JSON.stringify(feeds);
displayFeeds();
}

前三个函数代表了我们存储系统的整个封装。getFeeds 简单地检查 localStorage 的值,如果存在,则处理将 JSON 数据转换为原生 JavaScript 对象。addFeed 接受一个 feed 名称和 URL,创建一个简单的对象,并存储 JSON 版本。最后,removeFeed 函数简单地处理找到数组中的正确项,删除它,并将其存储回 localStorage

添加一个 RSS feed

目前一切顺利。现在让我们看看添加 feed 所需的逻辑。如果你记得,我们用来添加 feed 的链接指向addfeed.html。让我们来看看它:

Listing 13-4: addfeed.html
<!DOCTYPE html>
<html>
<head>
<title>Add Feed</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div data-role="page" id="addfeedpage" data-add-back-btn="true">
<div data-role="header">
<h1>Add Feed</h1>
</div>
<div data-role="content">
<form id="addFeedForm">
<div data-role="fieldcontain">
<label for="feedname">Feed Name:</label>
<input type="text" id="feedname" value="" />
</div>
<div data-role="fieldcontain">
<label for="feedurl">Feed URL:</label>
<input type="text" id="feedurl" value="" />
</div>
<input type="submit" value="Add Feed" data-theme="b">
</div>
<div data-role="footer">
<h4>Created with jQuery Mobile</h4>
</div>
</div>
</body>
</html>

除了表单外,这个页面没有太多内容。请注意,我们的表单没有 action。我们在这里不使用服务器。相反,我们的代码将处理表单提交并执行某些操作。还要注意,我们没有按照之前建议的做法——将 jQuery 和 jQuery Mobile 包含在顶部。在桌面应用程序中,这些包含是必需的,因为用户可能会将页面添加到应用程序的主页之外的书签中。由于该代码的最终目标是 PhoneGap 应用程序,我们不必担心这一点。这使得我们的 HTML 文件稍微小了一点。现在让我们返回到main.js,看看处理这一逻辑的代码。

以下代码是main.jsinit方法的片段。它处理表单上的按钮点击:

Listing 13-5: Add Feed event registration logic
//Listen for the addFeedPage so we can support adding feeds
$("#addfeedpage").live("pageshow", function(e) {
$("#addFeedForm").submit(function(e) {
handleAddFeed();
return false;
});
});

现在我们可以看看handleAddFeed了。我已经将这段代码抽象出来,只是为了简化事情:

Listing 13-6: handleAddFeed
function handleAddFeed() {
var feedname = $.trim($("#feedname").val());
var feedurl = $.trim($("#feedurl").val());
//basic error handling
var errors = "";
if(feedname == "") errors += "Feed name is required.\n";
if(feedurl == "") errors += "Feed url is required.\n";
if(errors != "") {
//Create a PhoneGap notification for the error
navigator.notification.alert(errors, function() {});
} else {
addFeed(feedname, feedurl);
$.mobile.changePage("index.html");
}
}

在大部分情况下,这里的逻辑应该很容易理解。我们获取 feed 名称和 URL 值,确保它们不为空,并可选地提醒任何错误。如果没有发生错误,那么我们运行之前描述的addFeed方法。请注意,我们使用changePageAPI 返回用户到主页。

我在这里特别指出一段代码,处理显示错误的那一行:

navigator.notification.alert(errors, function() {});

这一行来自于 PhoneGap API。它为您的设备创建了一个针对移动设备的特定警报通知。你可以把它想象成一个更高级的 JavaScript alert() 调用。第二个参数是警报窗口解除时的回调函数。因为我们在那种情况下不需要执行任何操作,所以我们提供了一个什么都不做的空回调。

查看 feed

当用户点击查看 feed 时会发生什么?这可能是应用程序中最复杂的部分。我们从 HTML 模板开始,这相当简单,因为大部分工作将在 JavaScript 中完成:

Listing 13-7: feed.html
<!DOCTYPE html>
<html>
<head>
<title>Feed</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div data-role="page" id="feedpage" data-add-back-btn="true">
<div data-role="header">
<h1></h1>
</div>
<div data-role="content" id="feedcontents">
</div>
<div data-role="footer">
<h4>Created with jQuery Mobile</h4>
</div>
</div>
</body>
</html>

这个页面基本上充当一个外壳。请注意,它根本没有真正的内容,只是空的 HTML 元素等待填充。让我们返回到main.js,看看这是如何工作的:

Listing 13-8: Feed display handler (part 1)
//Listen for the Feed Page so we can displaying entries
$("#feedpage").live("pageshow", function(e) {
//get the feed id based on query string
var query = $(this).data("url").split("=")[1];
//remove ?id=
query = query.replace("?id=","");
//assume it's a valid ID, since this is a mobile app folks won't be messing with the urls, but keep
//in mind normally this would be a concern
var feeds = getFeeds();
var thisFeed = feeds[query];
$("h1",this).text(thisFeed.name);
if(!feedCache[thisFeed.url]) {
$("#feedcontents").html("<p>Fetching data...</p>");
//now use Google Feeds API
$.get("https://ajax.googleapis.com/ajax/services/feed/ load?v=1.0&num=10&q="+encodeURI(thisFeed.url)+"&callback=?", {}, function(res,code) {
//see if the response was good...
if(res.responseStatus == 200) {
feedCache[thisFeed.url] = res.responseData.feed.entries;
displayFeed( thisFeed.url);
} else {
var error = "<p>Sorry, but this feed could not be loaded:</p><p>"+res.responseDetails+"</p>";
$("#feedcontents").html(error);
}
},"json");
} else {
displayFeed(thisFeed.url);
}
});

这段代码片段处理了对feed.html上的pageshow事件的监听。这意味着每次查看该文件时都会运行该代码,这正是我们想要的,因为它用于每个不同的 feed。这是如何工作的?记得我们的 feeds 列表包括了 feed 本身的标识符:

for(var i=0; i<feeds.length; i++) {
s+= "<li><a href='http://feed.html?id="+i+"' data- feed='"+i+"'>"+feeds[i].name+"</a> <a href='http:// class='deleteFeed' data-feedid='"+i+"'>Delete</a></li>";
}

jQuery Mobile 通过数据("url")API 为我们提供了对 URL 的访问。由于这会返回整个 URL,而我们只关心问号后的内容,因此我们可以使用一些字符串函数来清理它。最终结果是一个数值查询,我们可以使用它来从我们的 feed 查询中提取数据。在常规的桌面应用程序中,用户很容易搞乱 URL 参数。因此,我们在这里进行一些检查,以确保请求的值确实存在。由于这是一个移动设备上的单用户应用程序,因此不需要担心这个问题。

在我们尝试获取 feed 之前,我们利用了一个简单的缓存系统。在 main.js 中的第一行创建了一个空对象:

//used for caching
var feedCache= {};

此对象将存储我们的 feeds 结果,以便我们不必不断重新获取它们。这就是为什么有下面这行代码:

if(!feedCache[thisFeed.url]) {

在我们执行任何额外的网络调用之前运行。那么我们如何实际获取 feed 呢?Google 有一个很酷的服务叫做 Feed API(developers.google.com/feed/)。它允许我们使用 Google 来处理获取 RSS feed 的 XML 并将其转换为 JSON。JavaScript 可以处理 XML,但 JSON 更容易,因为它变成了常规的、简单的 JavaScript 对象。我们有一些错误处理,但如果一切顺利,我们只需缓存结果。最后一部分是对 displayFeed: 的调用:

Listing 13-9: displayFeed
function displayFeed(url) {
var entries = feedCache[url];
var s = "<ul data-role='listview' data-inset='true' id='entrylist'>";
for(var i=0; i<entries.length; i++) {
var entry = entries[i];
s += "<li><a href ='entry.html?entry="+i+"&url="+encodeURI(url)+"'>"+ entry.title+"</a></li>";
}
s += "</ul>";
$("#feedcontents").html(s);
$("#entrylist").listview();
}

前面的代码块只是迭代了结果 feed。当 Google 解析 feed 中的 XML 时,它转换为我们可以循环的对象数组。虽然 feed 中有许多我们可能感兴趣的属性,但我们只关心标题。注意我们如何构建我们的链接。我们传递数值索引和 URL(我们将在下一部分中使用)。然后,这被呈现为一个简单的 jQuery Mobile listview。

创建条目视图

准备好了最后一部分了吗?让我们来看看个别条目的显示。与之前一样,我们将从模板开始:

Listing 13-10: entry.html
<!DOCTYPE html>
<html>
<head>
<title>Entry</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div data-role="page" id="entrypage" data-add-back-btn="true">
<div data-role="header">
<h1></h1>
</div>
<div data-role="content">
<div id="entrycontents"></div>
<a href ="" id="entrylink" data-role="button">Visit Entry</a>
</div>
<div data-role="footer">
<h4>Created with jQuery Mobile</h4>
</div>
</div>
</body>
</html>

与之前的 feed.html 类似,entry.html 是一个空壳。请注意,标题、内容和链接都是空的。所有这些都将被真实的代码替换。让我们返回到 main.js 并查看处理此页面的代码:

Listing 13-11: Entry page event handler
$("#entrypage").live("pageshow", function(e) {
//get the entry id and url based on query string
var query = $(this).data("url").split("?")[1];
//remove ?
query = query.replace("?","");
//split by &
var parts = query.split("&");
var entryid = parts[0].split("=")[1];
var url = parts[1].split("=")[1];
var entry = feedCache[url][entryid];
$("h1",this).text(entry.title);
$("#entrycontents",this).html(entry.content);
$("#entrylink",this).attr("href",entry.link);
});

那么这里发生了什么?记得我们传递了一个索引值(点击了哪个条目,第一个,第二个?)和 feed 的 URL。我们从 URL 中解析出这些值。一旦我们知道了 feed 的 URL,我们就可以使用我们的缓存来获取特定的条目。一旦我们有了这个,更新标题、内容和链接就是一件简单的事情了。就是这样!

更进一步

现在,您可以从此应用程序中获取代码,并将其上传到 PhoneGap Build 服务,以便在您自己的设备上尝试。但是我们还能做些什么?以下是考虑的一些事项:

  • PhoneGap 提供了一个连接 API(docs.phonegap.com/en/1.4.1/phonegap_connection_connection.md.html),返回设备连接状态的信息。你可以添加对此的支持,以防止用户在设备离线时尝试阅读订阅。

  • 虽然我们将用户的订阅存储在localStorage中,但从阅读 RSS 条目缓存的数据是临时存储的。你也可以存储这些数据,并在用户离线时使用它。

  • PhoneGap 有一个出色的插件 API,并且已经有很多插件可用(github.com/phonegap/phonegap-plugins)。其中一个插件可以更轻松地发送短信。你可以添加一个选项,通过短信向朋友发送条目标题和链接。我们提到过 PhoneGap 还让你可以使用你的联系人,详细信息请参见联系人 API:docs.phonegap.com/en/1.4.1/phonegap_contacts_contacts.md.html

希望你能明白。这只是 jQuery Mobile 和 PhoneGap 强大功能的一个例子。

摘要

在本章中,我们利用了上一章学到的 PhoneGap 知识,创建了一个完整但相当简单的移动应用程序,利用了 jQuery Mobile 来进行设计和交互。

posted @ 2024-05-19 20:12  绝不原创的飞龙  阅读(5)  评论(0编辑  收藏  举报