jQuery2 高级教程(十一)
二十八、页面、主题和布局
在这一章中,我描述了 jQuery Mobile 应用的一个关键构件:页面。我在第二十七章中提到了页面,但现在我将深入细节并展示如何定义、配置和在页面间导航。我还将向您展示两个有用的 jQuery Mobile 特性,用于样式化和结构化页面中的内容:主题和网格布局。表 28-1 对本章进行了总结。
表 28-1 。章节总结
| 问题 | 解决办法 | 列表 |
|---|---|---|
| 定义一个 jQuery Mobile 页面。 | 将data-role属性应用于值为page的元素。 | one |
| 向页面添加页眉或页脚。 | 使用值header或footer将data-role属性应用于元素。 | Two |
| 在文档中定义多个页面。 | 创建几个data-role为page的元素。 | three |
| 在页面间导航。 | 创建一个a元素,其href元素是页面元素的id。 | four |
为a元素指定过渡效果。 | 应用data-transition属性。 | five |
| 设置全局过渡效果。 | 给defaultPageTransition设置赋值。 | six |
| 链接到另一个文档中的页面。 | 将文档的 URL 指定为一个a元素的href值。 | 7, 8 |
| 禁用单个链接的 Ajax。 | 将data-ajax属性设置为false。 | nine |
| 全局禁用 Ajax。 | 将ajaxEnable事件设置为false。 | Ten |
| 预取一页。 | 使用data-prefetch属性。 | 11, 12 |
| 更改当前页面。 | 使用changePage方法。 | Thirteen |
| 控制过渡效果的方向。 | 使用changePage方法的reverse设置。 | Fourteen |
| 指定显示加载对话框的延迟时间。 | 使用loadMsgDelay设置。 | Fifteen |
| 禁用加载对话框。 | 使用showLoadMsg设置。 | Sixteen |
| 确定当前页面。 | 使用activePage属性。 | Seventeen |
| 在后台加载页面。 | 使用loadPage方法。 | Eighteen |
| 响应页面加载。 | 使用页面加载事件。 | Nineteen |
| 响应页面转换。 | 使用页面转换事件。 | Twenty |
| 将样本应用于页面或元素。 | 使用data-theme属性,并将值设置为应该使用的样本。 | 21, 22 |
| 在网格中布置元素。 | 使用 jQuery Mobile 布局 CSS 类。 | Twenty-three |
了解 jQuery Mobile 页面
在第二十七章中,我向您展示了如何使用具有特定角色的元素在 HTML 文档中定义 jQuery Mobile 页面。概括一下,清单 28-1 显示了一个简单的页面。
清单 28-1 。HTML 文档中的简单 jQuery Mobile 页面
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div data-role="page">
<div data-role="content">
This is Jacqui's Flower Shop
</div>
</div>
</body>
</html>
这是一个最小的页面,由两个关键元素组成,每个元素都有一个data-role 属性。角色为page的元素表示包含 jQuery Mobile 页面的 HTML 内容区域。正如我在第二十七章中提到的,jQuery Mobile 的一个关键特性是显示给用户的页面与包含它们的 HTML 元素没有直接关系。
另一个重要的元素有content 的作用。这表示 jQuery Mobile 页面中包含页面内容的部分。一个页面可以包含不同的部分,其中的内容只有一个,我将很快演示。您可以在图 28-1 中看到清单中的 HTML 是如何在浏览器中显示的。
图 28-1 。在浏览器中显示最小的 jQuery Mobile 页面
向页面添加页眉和页脚和
除了内容部分,jQuery Mobile 页面还可以包含页眉和页脚,由元素表示,这些元素的data-role属性分别设置为header和footer。清单 28-2 展示了添加到示例页面中的这两个部分。
清单 28-2 。向示例页面添加页眉和页脚
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is Jacqui's Flower Shop
</div>
<div data-role="footer">
<h1>Home Page</h1>
</div>
</div>
</body>
</html>
你可以在图 28-2 中看到这些添加的效果。
注意页眉页脚在小屏幕上可以占据很大空间,如图所示。
图 28-2 。向页面添加页眉和页脚
提示注意,页脚显示在内容部分的末尾,而不是页面的底部。您可以通过将
data-position属性设置为fixed来固定页眉和页脚的位置——这样可以保持页眉和/或页脚的位置,同时允许其余内容自由滚动。使用该选项时要彻底测试:不是所有的浏览器都支持固定页眉和页脚所需的 CSS 特性。
向文档添加页面
您可以在一个文档中定义多个 jQuery Mobile 页面。这对于简单的 web 应用非常有用,因为您可以将需要的所有内容打包到一个 HTML 文件中,这可以减少必须向服务器发出的请求数量和必须传输的数据总量(因为有些元素——如head部分中的元素——对于多个页面只指定一次)。清单 28-3 显示了一个多页文档。
清单 28-3 。在 HTML 文档中定义多个 jQuery Mobile 页面
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<divid="page1"data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is Jacqui's Flower Shop
</div>
</div>
<div id="page2" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is page 2
</div>
</div>
</body>
</html>
本示例定义了文档中的两个页面。我使用了id属性给每个页面分配一个唯一的标识符,这些值构成了页面间导航的基础。加载 HTML 文档时,只显示第一页。为了让用户在页面间导航,我添加了一个a元素,它的href是目标页面的id,如清单 28-4 所示。
清单 28-4 。在页面间导航
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is Jacqui's Flower Shop
<p><a href="#page2">Go to page 2</a></p>
</div>
</div>
<div id="page2" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is page 2
<p><a href="#page1">Go to page 1</a></p>
</div>
</div>
</body>
</html>
在这个例子中,我在页面之间添加了链接。当一个链接被点击时,jQuery Mobile 会显示文档中相应的页面,如图 28-3 所示。
图 28-3 。在文档的页面间导航
配置页面过渡
当用户在页面之间导航时,jQuery Mobile 使用动画效果在一个页面和下一个页面之间切换。默认的效果叫做slide ,即将出页滑向左边,而新页从右边滑入。jQuery Mobile 定义了许多不同的效果,如下所示:
slidepopslideupslidedownslidefadefadeflipturnflownone(意为无效果,也表示为null)
并非所有移动设备都正确支持所有转换,您可能会遇到闪烁和断断续续的情况。jQuery Mobile 的每个新版本都增加了可以支持所有转换的设备数量,但是您应该始终进行彻底的测试,以确保您在目标设备上看不到任何问题。如果有疑问,试试fade 或slide过渡,我发现它们在最少的设备上有问题。
提示移动浏览器模拟器不能很好地处理过渡,通常会忽略它们。然而,它们在真实的移动设备上运行良好。如果你想在桌面上看到过渡,那么使用谷歌 Chrome 或苹果 Safari,这两种浏览器都能很好地处理效果。
通过使用a元素上的data-transition 属性,将值设置为您想要的效果,您可以更改单个页面过渡的动画方式。清单 28-5 提供了一个例子。
清单 28-5 。使用数据转换 属性
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is Jacqui's Flower Shop
<p><a href="#page2" data-transition="turn">Go to page 2</a></p>
</div>
</div>
<div id="page2" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is page 2
<p><a href="#page1">Go to page 1</a></p>
</div>
</div>
</body>
</html>
注意我不能轻易用数字给你展示不同的动画效果。这个例子需要在浏览器中进行实验。你可以通过下载本书附带的源代码来避免输入 HTML,这些源代码可以从
Apress.com免费获得。
当用户点击突出显示的链接时,turn转换用于显示目标页面。turn效果仅应用于该单个链接。页面中的其他链接或同一文档中的其他页面将继续使用默认链接。如果要禁用动画效果,请将data-transition属性设置为none。
提示你可以通过将
data-direction属性应用到值为reverse的a元素来改变效果播放的方向。在“改变当前页面”一节中,我给出了一个反转过渡方向的例子,并解释了它为什么有用。
如果你想改变用于所有导航的动画效果,那么你需要设置一个全局选项。jQuery Mobile 定义了defaultPageTransition 设置,可以在mobileinit事件被触发时进行设置。清单 28-6 展示了这是如何做到的。
清单 28-6 。更改默认页面过渡
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript">
$(document).bind("mobileinit", function() {
$.mobile.defaultPageTransition = "fade";
})
</script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is Jacqui's Flower Shop
<p><a href="#page2">Go to page 2</a></p>
</div>
</div>
<div id="page2" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is page 2
<p><a href="#page1">Go to page 1</a></p>
</div>
</div>
</body>
</html>
没有方便的方法为mobileinit事件注册一个处理函数,所以你必须选择document对象并使用bind方法。该方法的参数是您要处理的事件的名称以及事件被触发时要使用的处理函数。
注意jQuery Mobile 脚本库一加载就触发
mobileinit事件,这意味着在script元素中引用 jQuery Mobile 脚本库之前,您必须注册处理函数来更改全局 jQuery Mobile 设置。您可以在清单中看到我是如何做到的。如果在加载 jQuery Mobile 代码的script元素之前没有定义对bind方法的调用,那么这个函数将永远不会被执行。
要更改全局设置的值,您需要为$.mobile对象的属性分配一个新值。因为我想改变defaultPageTransition的设置,我给$.mobile.defaultPageTransition属性赋值,如下所示:
...
$.mobile.defaultPageTransition = "fade";
...
该语句将默认效果设置为fade。我仍然可以用data-transition属性覆盖这个设置。
链接到外部页面
您不必在一个文档中包含所有页面。您可以像使用常规 HTML 一样添加链接。为了演示这一点,我创建了一个名为document2.html 的新文件,其内容如清单 28-7 所示。
清单 28-7 。document2.html 文件的内容
<!DOCTYPE html>
<html>
<head>
<title>Document 2</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is page 1 in document2.html
<p><a href="#page2">Go to page 2 in this document</a></p>
<p><a href="example.html">Return to example.html</a></p>
</div>
</div>
<div id="page2" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is page 2 in document2.html
<p><a href="#page1">Go to page 1</a></p>
</div>
</div>
</body>
</html>
该文档包含一对 jQuery Mobile 页面,遵循与其他示例相同的结构。链接到其他文档中的页面很简单。您只需定义一个a元素,其href属性包含目标文档的 URL,如清单 28-8 所示。
清单 28-8 。导航到另一个 HTML 文档中的页面
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is Jacqui's Flower Shop
<p><a href="#page2">Go to page 2</a></p>
<p><a href="document2.html">Go to document2.html</a></p>
</div>
</div>
<div id="page2" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is page 2
<p><a href="#page1">Go to page 1</a></p>
</div>
</div>
</body>
</html>
jQuery Mobile 使用 Ajax 加载指定的文档,并自动显示第一页,如果指定了过渡效果,还会使用过渡效果。你可以在图 28-4 中看到结果。
图 28-4 。导航到另一个文档中的页面
提示 jQuery Mobile 自动将其样式和增强应用于通过 Ajax 加载的远程文档。这意味着您不必将 jQuery 和 jQuery Mobile 的
script和link元素包含在文件中,例如我在示例中使用的document2.html文件。也就是说,我建议您包含这些引用,因为这可能会阻止 jQuery Mobile 在发出此类请求时使用 Ajax,如果这样做了,那么内容的自动处理就不会执行。
处理 Ajax/页面 ID 问题
当链接到其他文档的页面时,并不是一帆风顺的。Ajax 内容的管理方式和 jQuery Mobile 页面的定义方式之间存在冲突。两者都依赖于元素的id属性的值。图 28-5 显示了这个问题。
图 28-5 。多页面 Ajax 问题
在这个图中,我点击了应该显示document2.html中的page2元素的链接,但我得到的实际上是example.html中的page2元素,这是一个令人困惑和意想不到的结果。
你可以用两种方法来解决这个问题。首先是每个 HTML 文档只定义一个 jQuery Mobile 页面——这是 jQuery Mobile 团队的建议。
第二种方法是在加载多页文档时禁用 Ajax。这解决了这个问题,但是这意味着 jQuery Mobile 在显示新页面时无法应用过渡效果。您可以通过将data-ajax属性设置为false来禁用单个a元素的 Ajax,如清单 28-9 所示。
清单 28-9 。禁用单个链接的 Ajax
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is Jacqui's Flower Shop
<p><a href="#page2">Go to page 2</a></p>
<p><a href="document2.html"data-ajax="false">Go to document2.html</a></p>
</div>
</div>
<div id="page2" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is page 2
<p><a href="#page1">Go to page 1</a></p>
</div>
</div>
</body>
</html>
在这个例子中,我为导航到document2.html 的链接禁用了 Ajax。如图图 28-6 所示,这产生了预期的导航序列。
图 28-6 。禁用 Ajax 以避免元素 id 冲突
默认情况下,您可以使用ajaxEnabled全局设置关闭 Ajax,这在清单 28-10 中有演示。当该设置为false时,除非将data-ajax属性应用于值为true的元素,否则 Ajax 不会用于导航。
清单 28-10 。使用全局设置禁用 Ajax
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript">
$(document).bind("mobileinit", function() {
$.mobile.ajaxEnable = false
})
</script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is Jacqui's Flower Shop
<p><a href="#page2">Go to page 2</a></p>
<p><a href="document2.html">Go to document2.html</a></p>
</div>
</div>
<div id="page2" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is page 2
<p><a href="#page1">Go to page 1</a></p>
</div>
</div>
</body>
</html>
预取页面
您可以让 jQuery Mobile 预取文档,这样当用户单击一个链接时,它们包含的页面就可以立即使用。这样做的好处是您创建了一个响应速度更快的应用,但是您是通过下载用户可能不需要的内容来做到这一点的。为了演示这个特性,我创建了一个名为singlepage.html 的文档,其内容如清单 28-11 所示。
清单 28-11 。singlepage.html 档案
<!DOCTYPE html>
<html>
<head>
<title>Single Page</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is the only page in this document
<p><a href="example.html">Return to example.html</a></p>
</div>
</div>
</body>
</html>
决定是否预取内容
预取内容是一个困难的决定。从应用的角度来看,预取是一个好主意,因为当用户在页面之间导航时,预取会产生即时响应。当移动连接速度慢、覆盖不稳定时,这一点尤为重要。用户不喜欢等待,如果内容不可用,持续掉线的连接将使您的应用不可用。
另一方面,你冒着下载内容的风险,因为你预料到用户可能不会进行导航操作。当移动数据计划对下载数据收取惩罚性费用并且每月带宽限制较低时,这可能是不受欢迎的。通过预取内容,您假设用户认为您的应用足够重要,可以用带宽(和成本)来换取性能,但事实可能并非如此。令人难过的事实是,尽管你可能在过去的一年里一直生活和呼吸着你的项目,但它对你的用户来说可能只不过是一种温和的便利。
我的建议是而不是预取页面。对于那些认为你的应用足够重要的用户,你可以给他们一个选项来启用预取。
您可以通过将data-prefetch属性应用到a元素并将其设置为true来启用预取。清单 28-12 显示了应用于example.html文档的data-prefetch属性。
清单 28-12 。预取内容
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is Jacqui's Flower Shop
<p><a href="#page2">Go to page 2</a></p>
<p>
<a href="singlepage.html" data-prefetch="true">Go to singlepage.html</a>
</p>
</div>
</div>
<div id="page2" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is page 2
<p><a href="#page1">Go to page 1</a></p>
</div>
</div>
</body>
</html>
在这个例子中,我让 jQuery Mobile 预取我的 URL 的目标。当我点击链接时,jQuery Mobile 能够导航到预取的内容,避免任何延迟。
提示当你在一个快速、可靠的网络上进行开发时,很难确定预取等功能是否有效。我喜欢通过使用调试 HTTP 代理来检查这些特性,它向我显示了从浏览器发送的请求。如果你是 Windows 用户,那么我推荐 Fiddler,这是一个优秀的工具,可以无限配置和定制。提琴手可以从
www.fiddler2.com下载。
使用脚本控制 jQuery Mobile 页面
你不需要总是依赖用户点击链接来管理页面导航。幸运的是,jQuery Mobile 为您提供了允许您使用 JavaScript 控制导航的方法和设置。在接下来的小节中,我将向您展示如何利用这些方法来获得对 jQuery Mobile web 应用中导航的细粒度控制。
更改当前页面
changePage方法 允许您更改 jQuery Mobile 显示的页面。清单 28-13 展示了这个方法的基本用法,当点击一个按钮时,它改变显示的页面。
清单 28-13 。更改 jQuery Mobile 显示的页面
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript">
$(document).bind("pageinit", function() {
$("button").bind("tap", function(e) {
var target = this.id == "local" ? "#page2" : "document2.html";
$.mobile.changePage(target)
})
});
</script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
<fieldset class="ui-grid-a">
<div class="ui-block-a"><button id="local">Local</button></div>
<div class="ui-block-b"><button id="remote">Remote</button></div>
</fieldset>
</div>
</div>
<div id="page2" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is page 2
<p><a href="#page1">Go to page 1</a></p>
</div>
</div>
</body>
</html>
在这个例子中,我添加了两个按钮,当单击时会调用changePage方法。我使用bind方法监听的事件是tap,这是 jQuery Mobile 定义的一小组有用的自定义事件之一。当用户点击屏幕(或在非触摸设备上点击鼠标)时,触发此事件。我在第二十七章的中描述了这个事件,以及其余的 jQuery Mobile 事件。
按钮是标准的 HTML 元素,jQuery Mobile 会自动将其转换成按钮小部件。我在第三十章中描述了配置 jQuery Mobile 按钮的选项。最后,你会注意到我已经给类ui-grid-a、ui-block-a和ui-block-b分配了一些元素。这些是 jQuery Mobile 对创建页面布局的支持的一部分,我将在本章稍后描述。这个例子的结果非常简单,如图 28-7 所示。当用户单击其中一个按钮时,调用changePage方法,传递本地页面的id值或另一个文档的 URL 供 jQuery Mobile 显示。内容被加载,并显示过渡效果,就像我使用常规链接时一样。
图 28-7 。使用 changePage 方法
这是changePage方法的基本用法,但是还有一些配置选项。为了配置页面转换,您将一个 settings 对象作为第二个参数传递给changePage方法,为一个或多个设置指定值。表 28-2 描述了可用的设置。这些设置中的大部分最好保留默认值,但是在接下来的部分中,我将展示两个更频繁修改的设置。
表 28-2 。changePage 方法的设置
| 环境 | 描述 |
|---|---|
allowSamePageTransition | 当设置为false(默认值)时,jQuery Mobile 将忽略目标页面为当前页面的changePage请求。值true允许这样的请求,尽管这会导致一些过渡动画的问题。 |
changeHash | 当true时,URL 栏中的哈希片段将被更新到新的位置(这样页面标识符就包含在 URL 中了)。默认为true。 |
data | 指定用于加载文档的 Ajax 请求中包含的数据。 |
dataUrl | 指定更新浏览器 URL 栏时使用的 URL。缺省值是 no value,这意味着该值取自内部页面的id或远程文档的 URL。 |
loadMsgDelay | 指定向用户显示加载图像的毫秒数。默认为50。 |
pageContainer | 指定应包含新页面的元素。 |
reloadPage | 当true时,jQuery Mobile 将重新加载远程文档的内容,即使数据已经被缓存。默认为false。 |
reverse | 当true时,过渡效果将向后播放。默认为false。 |
role | 设置新内容的data-role值——你可以在第二十九章的中看到这个设置的使用。 |
showLoadMsg | 当加载远程文件时,true值将显示加载图像。默认为true。 |
transition | 指定显示新页面时要使用的过渡效果。 |
type | 指定用于请求文档的 HTTP 方法。允许的值是get和post。默认是get。 |
提示这些选项也被
loadPage方法所使用,我将在本章稍后描述。
控制过渡效果的方向
reverse设定是我最常用的一个。jQuery Mobile 总是以相同的方式播放过渡效果,当您向用户呈现一个动作,有效地将他们送回之前的页面,或者您正在响应 jQuery Mobile swiperight事件时,这并不总是有意义的。清单 28-14 展示了如何解决这个问题。
清单 28-14 。过渡效果方向与导航意图不匹配
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript">
$(document).bind("pageinit", function() {
$.mobile.defaultPageTransition = "slide";
$("button").bind("tap", function(e) {
var target = this.id == "forward" ? "#page2" : "#page1";
$.mobile.changePage(target, {
reverse: (target == "#page1")
});
})
});
</script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is page 1
<button id="forward">Go to Page 2</button>
</div>
</div>
<div id="page2" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is page 2
<button id="back">Back to Page 1</button>
</div>
</div>
</body>
</html>
该文档有两个页面,每个页面都包含一个导航到另一个页面的按钮。第二页上的按钮标记为返回第一页。当点击第二页上的按钮时,我通过使用一个true的reverse值来改变过渡效果的方向。我无法在静态页面上显示这种效果,但这种效果感觉要自然得多。有一些潜意识的期望形成了,基于导航提示,动画应该播放,你是返回到上一页,而不是前进到新的一页。如果你在浏览器中查看这个例子,你就会明白我的意思。
控制负载动画
当 jQuery Mobile 通过 Ajax 加载远程文档超过 50 毫秒时,它会显示一个动画图像。当使用移动浏览器模拟器和高速网络时,jQuery Mobile 能够快速加载文档,以至于永远不会显示对话框。但是如果你使用一个实际的移动数据网络,或者像我所做的那样,在请求中引入一个延迟,那么这个对话框会在屏幕上停留足够长的时间来被看到,如图 28-8 所示。
图 28-8 。“jQuery Mobile 加载”对话框
您可以通过为loadMsgDelay设置提供一个值来改变对话框显示的时间间隔,如清单 28-15 所示。
清单 28-15 。更改加载对话框的延迟
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript">
$(document).bind("mobileinit", function() {
$.mobile.loadingMessage = "Loading Data..."
})
$(document).bind("pageinit", function() {
$("button").bind("tap", function(e) {
$.mobile.changePage("document2.html",{
loadMsgDelay: 1000
});
})
});
</script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
<button id="forward">Go</button>
</div>
</div>
</body>
</html>
在这个例子中,我已经指定 jQuery Mobile 在向用户显示加载对话框之前应该等待一秒钟。
提示您可以通过为全局
loadingMessage属性设置一个新值来更改加载对话框中的文本,如示例所示。与所有 jQuery Mobile 全局属性一样,这应该在触发mobileinit事件时执行的函数中设置。
当您调用changePage方法时,您可以通过为showLoadMsg设置指定false来禁用此对话框。我不建议这么做,因为给用户提供反馈总是一件好事,但是清单 28-16 显示了使用中的设置。
清单 28-16 。禁用加载对话框
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript">
$(document).bind("pageinit", function() {
$("button").bind("tap", function(e) {
$.mobile.changePage("document2.html", {
showLoadMsg: false
});
})
});
</script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
<button id="forward">Go</button>
</div>
</div>
</body>
</html>
确定当前页面
您可以使用$.mobile.activePage属性来确定 jQuery Mobile 正在显示的当前页面。清单 28-17 展示了activePage属性的使用。
清单 28-17 。使用 activatePage 属性
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript">
var eventHandlerCreated = false;
$(document).bind("pageinit", function () {
if (!eventHandlerCreated) {
$("button").bind("tap", function (e) {
var nextPages = {
page1: "#page2",
page2: "#page3",
page3: "#page1"
}
var currentPageId = $.mobile.activePage.attr("id");
$.mobile.changePage(nextPages[currentPageId]);
})
eventHandlerCreated = true;
}
});
</script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is page 1
<button id="forward">Go</button>
</div>
</div>
<div id="page2" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is page 2
<button id="Button1">Go</button>
</div>
</div>
<div id="page3" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is page 3
<button id="Button2">Go</button>
</div>
</div>
</body>
</html>
本例中有三个页面,每个页面都有一个按钮。当按钮被点击时,我读取activePage属性来获取当前页面。activePage属性返回一个包含当前页面的 jQuery 对象,所以我使用 jQuery attr方法来获取id属性的值。
我的脚本包括一个简单的映射,它告诉我文档中每个页面的下一页应该是什么,我使用从activePage属性获得的id值作为changePage方法的参数,确保我按照映射定义的顺序浏览页面。
提示注意,我使用了一个名为
eventHandlerCreated的变量来确保我只为tap事件创建一个处理函数。changePage方法触发pageinit事件,这会导致设置多个处理函数——这是 jQuery Mobile 应用中的一个常见问题,如果单击一个按钮会导致多个页面转换,这也是可能的原因。防止这个问题的最可靠的方法是使用一个像例子中这样的变量。
在后台加载页面
您可以使用loadPage方法 加载远程文档,而不向用户显示它们。这相当于我在本章前面演示的预取。loadPage方法有两个参数。第一个是要加载的文档的 URL,第二个是可选的设置对象。loadPage方法支持设置为changePage方法,我在表 28-2 中描述过。清单 28-18 显示了正在使用的loadPage方法。
清单 28-18 。使用 loadPage 方法
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript">
var loadedPages = false;
$(document).bind("pageinit", function () {
if (!loadedPages) {
$.mobile.loadPage("document2.html", {}).done(function () {
$("#gobutton").button("enable").bind("tap", function () {
$.mobile.changePage("document2.html");
loadedPages = true;
})
})
}
});
</script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
<button id="gobutton" disabled="disabled">Go</button>
</div>
</div>
</body>
</html>
提示注意,我传递了一个空的设置对象(
{})作为loadPage方法的第二个参数。jQuery 1 . 3 . 1 版中有一个缺陷,即使没有更改设置,也需要设置对象。
在这个例子中,我使用了loadPage方法来预加载document2.html文件。loadPage方法返回一个延迟对象,当页面加载后,您可以用它来接收通知。我在第三十五章的中解释了延迟对象,但是现在只要知道你可以在由loadPage方法返回的对象上调用done方法,指定一个当由loadPage启动的 Ajax 请求完成时将被执行的函数就足够了。
在这个例子中,我使用 jQuery UI 按钮小部件上的enable方法来启用页面中的按钮,并为tap事件注册一个句柄。当按钮被单击时,我调用changePage方法导航到预取的文档。(我在第三十章中描述了 jQuery Mobile 对按钮的支持。)
注意,我定义了一个名为loadedPages的变量。这解决了我在使用changePage方法(内部调用loadPage)时遇到的相同问题:每当 jQuery Mobile 初始化页面时,就会触发pageinit事件。这意味着当例子中的文档被加载时,事件被触发,当loadPage通过 Ajax 加载document2.html时,事件再次被触发。我使用loadedPages变量来确保我只尝试预加载一次内容。除非我启用了reload设置,否则调用loadPage两次(如果没有loadedPages变量就会发生这种情况)不会是世界末日。这将导致文档的缓存副本被忽略,并传输document.html两次。我将在下一节解释 jQuery Mobile 页面事件集。
使用页面事件
jQuery Mobile 定义了一组事件,您可以使用这些事件来接收关于页面变化的通知。这些事件在表 28-3 中有描述,我将在接下来的章节中展示一些更有用的事件。
表 28-3 。jQuery Mobile 页面事件
| 事件 | 描述 |
|---|---|
pagebeforecreate | 初始化页面时触发。 |
pagecreate | 当页面已经创建但大多数自动增强尚未执行时触发。 |
pageinit | 页面初始化后触发。 |
pageremove | 在移除页面之前触发。 |
pagebeforeload | 在通过 Ajax 请求页面之前触发。 |
pageload | 通过 Ajax 成功加载页面时触发。 |
pageloadfailed | 当页面无法通过 Ajax 加载时触发。 |
pagebeforechange | 在执行页面转换之前触发。 |
pagechange | 在执行页面转换后触发。 |
pagechangefailed | 当页面更改失败时触发(这通常是因为无法加载请求的文档)。 |
pagebeforeshow | 在向用户显示页面之前触发。 |
pagebeforehide | 在页面从显示中移除之前触发。 |
pageshow | 向用户显示页面后触发。 |
pagehide | 页面对用户隐藏后触发。 |
处理页面初始化事件
事件是最有用的 jQuery Mobile 页面事件,如第二十七章中的所述。当您想要使用脚本配置页面时,您需要响应的就是这个事件。我不打算再次演示这个事件,因为到目前为止您已经在每个示例中看到了它,但是我要强调的是,在使用 jQuery Mobile 时,使用标准的 jQuery $(document).ready()方法是不可靠的。
处理页面加载事件
pagebeforeload、pageload和pageloadfailed事件对于监控远程页面的 Ajax 请求非常有用,这些请求可以由 jQuery Mobile 自动生成,也可以通过changePage和loadPage方法以编程方式生成。在演示loadPage方法时,我使用了一个延迟对象来响应页面加载,但是您可以使用pageload方法(当然,还有出错时的pageloadfailed方法)获得相同的结果。清单 28-19 显示了更新后使用pageload事件的loadPage示例。
清单 28-19 。使用 pageload 事件
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript">
$(document).bind("pageload", function(event, data) {
if (data.url == "document2.html") {
$("#gobutton").button("enable").bind("tap", function() {
$.mobile.changePage("document2.html");
})
}
})
var loadedPages = false;
$(document).bind("pageinit", function() {
if (!loadedPages) {
loadedPages = true;
$.mobile.loadPage("document2.html", {});
}
});
</script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
<button id="gobutton" disabled>Go</button>
</div>
</div>
</body>
</html>
在这个例子中,我指定了一个函数,当pageload事件被触发时将执行这个函数。jQuery Mobile 通过将数据对象作为第二个参数传递给函数来提供关于请求的信息。我使用url属性来检查已经加载的文档是否是我所期望的。数据对象为pageload事件定义的属性集在表 28-4 中描述。从表中可以看到,大部分属性都对应于 jQuery Ajax 支持,我在第 14 和 15 章中描述过。
表 28-4 。页面加载数据对象事件属性
| 财产 | 描述 |
|---|---|
url | 返回传递给loadPage方法的 URL(这是 jQuery Mobile 在请求页面时使用的方法,也是changePage方法使用的方法)。 |
absUrl | 请求的绝对 URL。 |
options | Ajax 请求选项。关于配置 Ajax 的详细信息,请参见第十四章和第十五章。 |
xhr | 用于请求的 jQuery Ajax 请求对象。参见第十四章和第十五章了解该物体的详细信息。 |
textStatus | 请求状态的字符串描述。详见第十四章和第十五章。 |
响应页面转换
您可以使用页面转换事件在用户从一个页面导航到另一个页面时得到通知(或者当您使用changePage方法以编程方式这样做时)。这些事件(pagebeforehide、pagehide、pagebeforeshow和pageshow)在每次页面转换时都会被触发,即使该页面之前已经向用户显示过。清单 28-20 显示了其中一个事件的使用。
清单 28-20 。响应被隐藏的页面
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript">
var registeredHandlers = false;
$(document).bind("pageinit", function() {
if (!registeredHandlers) {
registeredHandlers = true;
$("#page1").bind("pagehide", function(event, data) {
$.mobile.changePage($("#page1"));
})
}
});
</script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
<a href="document2.html">Go to document2.html</a>
</div>
</div>
</body>
</html>
在这个例子中,我通过选择我想要的元素并调用bind方法,为page1元素上的pagehide事件注册了一个处理函数。这意味着只有当选定的页面被隐藏时,我才会收到事件。这是一个相当愚蠢的例子,因为每当pagehide事件被触发时,它只是使用changePage方法返回到page1,但是它确实演示了事件的用法。请注意,我仍然使用变量来确保只注册一次处理函数。如果我没有这样做,那么当document2.html页面被加载时,两个函数将在同一个元素上为同一个事件注册。
应用 jQuery Mobile 主题
jQuery Mobile 提供了对主题的支持,更像是 jQuery UI 提供的主题支持的简化版本。您在第二十七章中下载并安装的 jQuery Mobile 文件中包含一个默认主题,您可以使用 jQuery Mobile ThemeRoller 应用创建自定义主题,该应用是您用于 jQuery UI 的同名应用的变体。
注意正如我在第二十七章中提到的,我不会在这本书的这一部分创建和使用自定义主题。jQuery Mobile ThemeRoller 应用没有预先构建的主题集合,并且很难用文字描述创建主题的过程。在这一章中我将使用默认主题,但是你可以在
http://jquerymobile.com/themeroller看到 jQuery Mobile ThemeRoller。
jQuery Mobile 主题由一个或多个样本组成,这些样本是一组应用于不同种类元素的样式。样本由一个字母识别,以 A 开始。默认主题有五个样本,命名为A到E。
要在 ThemeRoller 中查看默认主题,请导航至http://jquerymobile.com/themeroller;点击Import链接;并点击Import Default Theme链接,将jquery.mobile-1.3.1.css文件的内容导入对话框(这是你在第二十七章下载安装的 CSS 文件)。单击Import按钮,ThemeRoller 将处理 CSS 并显示默认色板,如图图 28-9 所示。
图 28-9 。默认主题中的样本
通过使用data-theme属性将主题应用到 jQuery Mobile 页面,将值设置为所需样本的名称。清单 28-21 提供了一个例子。
清单 28-21 。在主题中使用样本
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page" data-theme="a">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is Theme A
<a href="#page2" data-role="button">Switch Theme</a>
</div>
</div>
<div id="page2" data-role="page" data-theme="b">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is Theme B
<a href="#page1" data-role="button">Switch Theme</a>
</div>
</div>
</body>
</html>
我已经将data-theme属性应用到了page元素,其效果是将指定的样本应用到页面中的所有子元素。在这个例子中有两个页面,这样我就可以展示相同的内容是如何通过一对对比主题显示的——并指出在 jQuery Mobile 中,一旦页面通过了自动增强过程,就没有可靠的方法来更改主题。data-theme属性被转换成一组 CSS 类,这些类在页面初始化过程中应用于元素,因此改变属性值不会改变类。你可以在图 28-10 中看到两页的例子。
图 28-10 。同一应用中使用不同色板的两个页面
提示还有一个叫
active的色板,用来高亮显示选中的按钮。这是由 jQuery Mobile 自动应用的,但是您也可以直接使用它。如果你这样做了,确保你没有通过创建冲突的活动元素来混淆用户。
将样本应用到单个元素
上一个示例展示了如何设计整个页面的样式,但是您也可以在每个元素的基础上应用色板,混合和匹配以获得特定的效果。清单 28-22 提供了一个演示。
清单 28-22 。将色板应用到单个元素
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page"data-theme="a">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
<a href="document2.html" data-role="button"data-theme="b">Press Me</a>
<a href="document2.html" data-role="button"data-theme="c">Press Me</a>
<a href="document2.html" data-role="button"data-theme="e">Press Me</a>
</div>
</div>
</body>
</html>
在这个例子中,我将data-theme应用于页面和三个button元素,每个元素指定一个不同的样本。你可以在图 28-11 中看到效果。
图 28-11 。将不同的色板应用于同一页面中的元素
jQuery Mobile 对主题的支持简单易用。如果您能够动态地更改元素使用的样本,那就太好了,但是即使忽略了这一点,您也可以使用样本来定制移动应用的外观。
创建网格布局
jQuery Mobile 定义了一些有用的 CSS 类,您可以使用它们以网格的形式展示移动页面的内容。这是您自己可以做的事情,但是将它们内置到库中是有用的,并且减少了所需的定制开发量,尤其是对于简单的移动应用。jQuery Mobile 定义了四个网格类,每个类包含不同数量的列,如表 28-5 所示。
表 28-5 。jQuery Mobile 布局网格
| CSS 类 | 列 |
|---|---|
ui-grid-a | 2 |
ui-grid-b | 3 |
ui-grid-c | 4 |
ui-grid-d | 5 |
将一个网格类应用于容器元素,然后将类应用于其中的每个内容项,从每列的ui-block-a、ui-block-b开始,依此类推。清单 28-23 展示了使用这些类来创建一个简单的网格。
清单 28-23 。使用 jQuery Mobile 布局类创建网格
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page" data-theme="b">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
<divclass="ui-grid-b">
<divclass="ui-block-a"><button>Press Me</button></div>
<divclass="ui-block-b"><button>Press Me</button></div>
<divclass="ui-block-c"><button>Press Me</button></div>
</div>
<divclass="ui-grid-a">
<divclass="ui-block-a"><button>Press Me</button></div>
<divclass="ui-block-b"><button>Press Me</button></div>
</div>
<div><button>Press Me</button></div>
</div>
</div>
</body>
</html>
在这个例子中,我创建了两个网格:一个有三列,另一个有两列。每一列包含一个button元素,我在网格外添加了一个按钮来强调默认行为,这是为了让元素跨越屏幕。你可以在图 28-12 中看到结果。
图 28-12 。在网格中布局元素
摘要
在这一章中,我描述了页面,它是 jQuery Mobile 的关键构件之一。我还描述了 jQuery Mobile 对主题和网格布局的支持。这些特性为最重要的 jQuery Mobile 特性提供了基础:小部件。在第二十九章中,我从描述对话框和弹出窗口部件开始。
二十九、对话框和弹出窗口小部件
在这一章中,我将介绍前两个 jQuery Mobile 小部件:对话框和弹出窗口。jQuery Mobile 小部件的行为与 jQuery UI 中的小部件略有不同,但是——您将会了解到——有一个共同的方法来支持这两个库。表 29-1 对本章进行了总结。
表 29-1 。章节总结
| 问题 | 解决办法 | 列表 |
|---|---|---|
| 创建一个对话框小部件。 | 将值为 dialog 的data-role属性添加到包含对话框内容的div元素中,或将值为dialog的data-rel属性添加到将打开对话框的导航链接中。 | 1, 2 |
| 以编程方式创建对话框。 | 使用changePage方法。 | three |
| 向对话框添加按钮。 | 将a元素添加到对话框元素中。 | 4, 5 |
| 配置对话框。 | 使用配置数据属性或调用 dialog 方法并使用配置选项。 | 6, 7 |
| 关闭对话框。 | 调用close方法。 | eight |
| 创建一个弹出窗口小部件。 | 将值为popup的data-role属性添加到将显示小部件的 jQuery Mobile 页面中的div元素中。 | nine |
| 配置弹出窗口。 | 将数据属性应用于打开弹出窗口的a元素,或者包含弹出窗口的div元素,或者调用popup方法。 | 10–12 |
| 以编程方式控制弹出窗口。 | 使用open、close,和reposition方法。 | Thirteen |
| 响应弹出窗口中的更改。 | 处理弹出事件。 | Fourteen |
使用 jQuery Mobile 对话窗口小部件
顾名思义,对话框小部件为用户提供了一个对话框。因为这是我描述的第一个 jQuery Mobile 小部件,所以我将向您展示创建和管理小部件的不同方法,为本章的剩余部分和后面的章节做准备。
创建对话框小部件
当 jQuery Mobile 遇到一个元素的data-role属性被设置为dialog时,它会自动创建对话框小部件,如清单 29-1 所示。
清单 29-1 。使用数据角色属性以声明方式创建对话框小部件
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
<a href="#dialog1">Show the dialog</a>
</div>
</div>
<div id="dialog1" data-role="dialog">
<div data-role="header">
<h1>You clicked the link!</h1>
</div>
<div data-role="content">
This is the content area of the dialog
</div>
</div>
</body>
</html>
这个例子包含一个带有a元素的页面,当点击这个页面时,它将导航到名为dialog1的元素。dialog1元素的data-role属性被设置为dialog,这使得 jQuery Mobile 将元素及其内容显示为对话框,如图 29-1 中的所示。
图 29-1 。将页面显示为对话框
也可以通过将data-rel属性应用于导航a元素来创建对话框。在清单 29-2 中,您可以看到我如何将data-rel属性设置为dialog,以便从一个data-role属性设置为page的元素创建一个对话框小部件的实例。
清单 29-2 。使用 data-rel 属性从页面创建对话框小部件
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
<a href="#page2" data-rel="dialog">Show the dialog</a>
</div>
</div>
<div id="page2" data-role="page">
<div data-role="header">
<h1>You clicked the link!</h1>
</div>
<div data-role="content">
This is the content area of the dialog
</div>
</div>
</body>
</html>
在这个例子中,有两个常规的 jQuery Mobile 页面。第一页中的链接就像我在第二十八章中用于导航的链接一样,除了我已经应用了data-rel属性并将值设置为dialog。
以编程方式创建对话框小部件
声明性方法是有用的,但是它要求您确定内容在 HTML 中静态显示的方式。有时你会想要决定动态地将一个页面显示为一个对话框,这可以通过changePage方法和它支持的role设置来完成。清单 29-3 展示了使用changePage方法来创建一个对话框。
清单 29-3 。使用 changePage 方法以编程方式创建对话框
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script>
$(document).bind("pageinit", function (event, data) {
$("#dialogLink").click(function (e) {
$.mobile.changePage(this.href, {
role: "dialog"
});
});
});
</script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
<p><a id="dialogLink" href="#page2">Show the dialog</a></p>
<p><a href="#page2">Show the page</a></p>
</div>
</div>
<div id="page2" data-role="page">
<div data-role="header">
<h1>You clicked the link!</h1>
</div>
<div data-role="content">
This is page 2
<a href="#" data-role="button" data-rel="back">Close</a>
</div>
</div>
</body>
</html>
这种技术意味着你可以用不同的方式使用相同的内容。在清单中,我定义了两个链接,其中一个链接允许使用标准导航来加载在同一个 HTML 文档中定义的页面。我已经为来自另一个a元素的click事件定义了一个处理函数,我通过调用设置为dialog的role方法来处理它。这意味着页面的处理方式将取决于点击了哪个链接,如图 29-2 所示。
图 29-2 。以编程方式创建对话框
注意使用这种技术时需要小心,因为 jQuery Mobile 会缓存与内容相关联的角色——这意味着一旦您将页面显示为对话框,它将始终显示为
dialog,即使您使用page的role设置再次调用changePage(或者直到 HTML 文档被重新加载)。
向对话框添加按钮
通过向对话框的内容添加一个button元素,将data-role属性设置为 button,将data-rel属性设置为back,可以向对话框添加一个关闭按钮。我在第三十章中完整描述了 jQuery Mobile 按钮部件,但是你可以在清单 29-4 中看到它是如何应用于对话框部件的。
清单 29-4 。向对话框添加关闭按钮
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
<a href="#page2" data-rel="dialog">Show the dialog</a>
</div>
</div>
<div id="page2" data-role="page">
<div data-role="header">
<h1>You clicked the link!</h1>
</div>
<div data-role="content">
This is the content area of the dialog
<a href="#" data-role="button" data-rel="back">Close</a>
</div>
</div>
</body>
</html>
我不必为链接指定目标。我只是将href属性设置为#,并让 jQuery Mobile 来决定该做什么。这很有用,因为你可能想在不同的页面上显示一个对话框,但你不知道是哪个页面导致了这个对话框的显示,也不知道浏览器应该返回到哪里。图 29-3 显示了在对话框中添加这个元素的效果。
图 29-3 。在对话框中添加关闭按钮
您可以在对话框中添加更多的按钮,这些按钮包含更多的a元素,这些元素的href属性指向您想要显示的页面。这就是我在清单 29-5 中所做的,我在同一个 HTML 文档中添加了一个到另一个 jQuery Mobile 页面的链接。
提示如果你不想通过导航到一个新页面来响应一个按钮,那么你可以从
a元素中处理click事件,并使用close方法来关闭对话框——参见本章后面的“使用对话框方法”一节中的例子。
清单 29-5 。向对话框添加导航按钮
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
<a href="#page2" data-rel="dialog">Show the dialog</a>
</div>
</div>
<div id="page2" data-role="page" data-overlay-theme="d">
<div data-role="header">
<h1>You clicked the link!</h1>
</div>
<div data-role="content">
This is the content area of the dialog
<a href="#page3" data-role="button">OK</a>
<a href="#" data-role="button" data-rel="back">Close</a>
</div>
</div>
<div id="page3" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
This is page 3\. You came here via the dialog.
</div>
</div>
</body>
</html>
在这个例子中,我添加了一个将用户带到page3的a元素,我也将它添加到了文档中。图 29-4 显示了从对话框到新页面的导航。
图 29-4 。在对话框中添加导航链接/按钮
配置对话框小部件
对话框小部件定义了一组配置选项,既可以使用data属性以声明方式设置,也可以使用 JavaScript 方法调用来设置。我已经在表 29-2 中列出了两组选项,下面我将描述如何使用声明式和编程式配置。
表 29-2 。设置为对话框小工具
| 数据属性 | 环境 | 描述 |
|---|---|---|
data-close-btn | closeBtn | 获取或设置对话框标题中“关闭”按钮的位置。支持的值有left、right和none。 |
data-close-btn-text | closeBtnText | 获取或设置对话框标题中“关闭”按钮的文本。该文本不会显示给用户,但可由辅助功能软件检测到。 |
data-corners | corners | 获取或设置对话框是否应以圆角显示。默认值为true。 |
data-overlay-theme | overlayTheme | 获取或设置在其上绘制对话框的主题。该设置区分大小写,必须用小写表示。 |
在大多数情况下,使用数据属性配置小部件并让自动增强应用您的设置会更简单、更容易。这是标准的 jQuery Mobile 配置方法,您可以看到我是如何将它用于清单 29-6 中的data-overlay-theme属性的。
清单 29-6 。用数据属性配置对话框小部件
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
<a href="#dialog1">Show the dialog</a>
</div>
</div>
<div id="dialog1" data-role="dialog" data-overlay-theme="d">
<div data-role="header">
<h1>You clicked the link!</h1>
</div>
<div data-role="content">
This is the content area of the dialog
</div>
</div>
</body>
</html>
我已经指定将D样本用作对话框显示的覆盖图。您可以在图 29-5 中看到效果:对话框显示在浅色背景上,而不是与默认A样本相关的黑色背景上。(我在第二十八章中描述了主题和样本的 jQuery Mobile 方法。)
图 29-5 。用数据属性配置对话框小部件
通过调用 jQuery Mobile dialog方法,传入一个对象,该对象的属性对应于表 29-2 中您想要更改的设置,您可以在创建对话框小部件后对其进行配置。在清单 29-7 中,你可以看到我是如何使用dialog方法来配置对话框的。
清单 29-7 。以编程方式配置对话框小部件
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script>
$(document).bind("pageinit", function () {
$("#dialog1").dialog({
corners: false,
overlayTheme: "e"
});
});
</script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
<a href="#dialog1">Show the dialog</a>
</div>
</div>
<div id="dialog1" data-role="dialog" data-overlay-theme="d">
<div data-role="header">
<h1>You clicked the link!</h1>
</div>
<div data-role="content">
This is the content area of the dialog
</div>
</div>
</body>
</html>
您可以配置小部件来响应pageinit事件,在清单中您可以看到我是如何选择小部件下面的元素并对其调用dialog方法的。我传递给dialog方法的对象具有与表 29-2 中的设置相对应的属性,你可以看到我已经为corners和overlayTheme设置定义了新的值。传递给dialog方法的选项覆盖了data属性值,您可以在图 29-6 中看到效果。
图 29-6 。以编程方式配置对话框小部件
注意jQuery Mobile API 文档建议可以使用 jQuery UI 风格的
option方法调用来配置对话框小部件,像这样:$("#dialog1"), dialog("option," "corners," false)。但是,如果您使用这种方法,您将会看到一条错误消息,告诉您在小部件初始化之前不能调用方法。这个方法调用只有在小部件已经显示时才起作用,但是此时执行配置任务已经太晚了。相反,使用清单中所示的技术:将一个配置对象传递给dialog方法以响应pageinit事件。
使用对话框方法
对话框小部件只定义了一个方法,它以编程方式关闭对话框。我已经在表 29-3 中描述了该方法,以便您在将来执行快速搜索时可以更容易地找到它。
表 29-3 。对话方法
| 方法 | 描述 |
|---|---|
dialog("close") | 关闭对话框。 |
在清单 29-8 中,我创建了一个显示固定时间的对话框。除了close方法之外,我还使用了data-close-btn属性来移除菜单栏中的关闭按钮。
清单 29-8 。使用对话框关闭方法
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script>
$(document).bind("pageinit", function () {
$("#page1 a").click(function (e) {
var duration = 15;
$("#remaining").text(duration);
var interval = setInterval(function () {
$("#remaining").text(--duration);
if (duration == 0) {
clearInterval(interval);
$("#dialog1").dialog("close");
}
}, 1000);
});
});
</script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
<a href="#dialog1">Show the dialog</a>
</div>
</div>
<div id="dialog1" data-role="dialog" data-close-btn="none" data-overlay-theme="d">
<div data-role="header">
<h1>Important</h1>
</div>
<div data-role="content">
This in an important message that will be displayed
for <span id="remaining"></span> seconds.
</div>
</div>
</body>
</html>
本例中的script元素为打开对话框的链接被触发时触发的click事件设置一个处理程序。以编程方式打开对话框的唯一方法是使用changePage方法,所以我让默认事件动作负责打开对话框,并启动一个倒计时 15 秒的计时器。我每秒更新一次对话框显示的span元素的内容,并在计时器到期时调用对话框的close方法。结果是如图 29-7 所示的对话框。
图 29-7 。一个自动关闭对话框的小工具
有几点需要注意。首先,我不需要显式刷新对话框的内容来反映span元素的变化——对话框会自动更新自己。第二点是,虽然我创建了一个没有关闭按钮的对话框,但是用户仍然可以通过使用浏览器的后退按钮来关闭我的对话框。
使用对话框事件
jQuery Mobile dialog 小部件定义了一个事件,我已经在表 29-4 中描述过了。我从不使用这个事件,而是倾向于处理我在第二十八章中描述的页面级事件。
表 29-4 。对话事件
| 事件 | 描述 |
|---|---|
create | 创建对话框小部件时会触发此事件。 |
使用 jQuery Mobile 弹出窗口小部件
jQuery Mobile 弹出窗口小部件在弹出窗口中显示内容。弹出窗口是对话框的轻量级替代,但提供了更多的编程控制。
创建弹出窗口小部件
弹出窗口是通过将data-role属性应用到元素并将值设置为popup来创建的。弹出窗口不是自动显示的,而是当用户点击一个针对弹出窗口元素的a元素时打开的,该元素的data-rel属性也被设置为 popup。弹出窗口和打开它的链接必须在同一个 jQuery Mobile 页面中,如清单 29-9 所示。
清单 29-9 。创建 jQuery Mobile 弹出窗口小部件
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
<a href="#popup" data-rel="popup">Show the popup</a>
</div>
<div id="popup" data-role="popup">
<p>This is the popup content</p>
</div>
</div>
</body>
</html>
点击链接会弹出一个弹出窗口,如图图 29-8 所示。在弹出窗口之外单击会将其关闭。
图 29-8 。创建 jQuery Mobile 弹出窗口
配置弹出窗口小部件
如图所示,弹出窗口位于打开它的链接上,这很少是您想要的效果。您可以通过两种方式配置弹出窗口——或者配置打开弹出窗口的a元素,或者配置弹出窗口本身。
配置打开弹出窗口的链接
配置a元素的的优点是你可以多次使用同一个弹出窗口,但是应用不同的配置。缺点是只有两个配置选项——但是,幸运的是,它们是您可能想要调整的选项。我已经在表 29-5 中列出了可以应用于a元素的数据属性。
表 29-5 。打开弹出窗口的元素的数据属性
| 数据属性 | 描述 |
|---|---|
data-position-to | 指定弹出窗口相对于打开它的a元素的位置。选项在表 29-6 中描述。 |
data-transition | 指定用于显示弹出窗口的转换–参见第二十八章中的 jQuery Mobile 转换列表。 |
data-position-to属性指定弹出窗口相对于a元素的位置,可以设置为表 29-6 中所示的值。
表 29-6 。数据位置属性的值
| 价值 | 描述 |
|---|---|
origin | 将弹出窗口置于a元素的中心。 |
window | 将弹出窗口居中。 |
| 选择器 | 将弹出窗口置于与选择器匹配的第一个元素的中心。如果该元素不可见,则弹出窗口在窗口中居中。 |
在清单 29-10 中,你可以看到我是如何使用data-position-to属性通过选择器来改变弹出窗口的位置的。
清单 29-10 。通过打开弹出窗口的链接配置弹出窗口
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
<style>
#anchor { position: absolute; right: 10px; }
</style>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
<a href="#popup" data-rel="popup"
data-position-to="#anchor">Show the popup</a>
<span id="anchor">Anchor</span>
</div>
<div id="popup" data-role="popup">
<p>This is the popup content</p>
</div>
</div>
</body>
</html>
我使用了选择器选项,为打开弹出窗口的a元素上的data-position-to属性的值指定了#anchor。这个选择器匹配一个div元素的id,我已经用 CSS 将其放置在窗口的右边缘。在图 29-9 中可以看到效果。
图 29-9 。通过 a 元素配置弹出窗口的位置
直接配置弹出窗口
当您直接配置小部件时,有更多配置选项可用。和对话框部件一样,你可以用data属性或者通过popup方法来配置弹出窗口,我已经在表 29-7 中列出了这两种方法。大多数配置选项是不言而喻的,或者类似于dialog小部件所使用的选项。
表 29-7 。对话框小部件的设置
| 数据属性 | 环境 | 描述 |
|---|---|---|
data-corners | corners | 指定弹出窗口是否用圆角绘制。默认为true。 |
data-dismissable | dismissable | 如果设置为false,当用户点击小工具外部时,弹出窗口不会消失。默认为true。 |
data-history | history | 指定在弹出窗口打开之前是否创建历史项目。默认为true,表示点击浏览器后退按钮时浏览器关闭。 |
data-overlay-theme | overlayTheme | 指定用于覆盖的主题。默认为null,呈现透明背景。 |
data-position-to | positionTo | 使用表 29-6 中的值指定弹出窗口的位置。 |
data-shadow | shadow | 指定弹出窗口是否用阴影绘制。默认为true。 |
data-tolerance | tolerance | 指定弹出窗口和窗口边缘之间的最小距离。默认值为30, 15, 30, 15。 |
data-transition | transition | 指定弹出窗口打开和关闭时使用的过渡。 |
使用历史设置
导致弹出窗口部件最混乱的设置是data-history,它决定了在弹出窗口打开之前是否在浏览器历史中创建一个新条目。这个设置的效果意味着弹出窗口被浏览器的后退按钮关闭——但是这个特性并不总是有意义的,特别是当弹出窗口被打开和关闭以响应一个触摸事件时,如清单 29-11 所示。
清单 29-11 。弹出历史条目和鼠标触发器的效果
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
<script>
var mouseHandlerSet = false;
$(document).bind("pageinit", function () {
if (!mouseHandlerSet) {
$("#page1 a").mouseenter(function (e) {
$("#popup").popup("open", {
x: e.pageX, y: e.pageY
});
});
$("#popup").mouseleave(function (e) {
$(this).popup("close");
});
mouseHandlerSet = true;
}
});
</script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
<p><a href="#popup" data-rel="popup">Popup</a></p>
</div>
<div id="popup" data-role="popup" data-history="false">
<p>This is the popup content</p>
</div>
</div>
</body>
</html>
这个例子使用了弹出菜单open 和close方法,我将在本章后面描述,这样当用户将鼠标或指针移到a元素上时弹出菜单就会显示,当用户将鼠标移出弹出菜单时弹出菜单就会隐藏(我使用了一个传递给open方法的配置选项来确保弹出菜单在鼠标指针下打开)。
在这种情况下,用户可能不希望后退按钮简单地关闭弹出窗口,因为首先没有执行显式导航来打开它——这是考虑data-history 属性以创建一致体验的好机会。
提示我正在仔细限定这个配置设置的使用,因为理解这个机制只是围绕弹出窗口使用的混乱的一部分。另一个问题是决定采用哪种方法——这只能在应用的其余部分中决定。这种情况下的用户期望很难预测,只有用户测试才能告诉你哪种方法能为你的 web 应用创造自然的体验。不要试图逃避测试,简单地将它作为一个可配置的选项——大多数用户将不一致的行为归因于糟糕的实现,并且不会努力去看看是否可以改变。
使用弹出窗口呈现丰富的内容
弹出窗口可以用来呈现丰富的内容,弹出窗口的一个常见用途是向用户呈现一组图像缩略图,这些缩略图可以在弹出窗口中打开全尺寸图像,这就是我在清单 29-12 中所做的。(我在本书附带的apress.com的免费下载中包含了这个例子中的图片。)
清单 29-12 。使用弹出菜单显示丰富的内容
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
<style>
.smallImage { height: 40%; width: 40%; padding: 5px}
</style>
<script>
$(document).bind("pageinit", function () {
var data = ["beach.png", "clouds.png", "fishing.png", "storms.png"];
for (var i = 0; i < data.length; i++) {
$("<img>").addClass("smallImage").attr("src",
data[i]).appendTo("#contentHolder");
}
$("#popup").popup({
corners: false,
overlayTheme: "a"
});
$("#contentHolder img").bind("tap", function (e) {
var maxHeight = $(window).height() - 10 + "px";
$("#LgImage").attr("src", e.target.src).css("max-height", maxHeight);
$("#popup").popup("open");
});
});
</script>
</head>
<body>
<div id="page1" data-role="page" data-theme="d">
<div id="contentHolder" data-role="content"></div>
<div id="popup" data-role="popup" data-history="true">
<img id="LgImage" class="zoomImg" src="" />
</div>
</div>
</body>
</html>
我使用一个for循环来生成一组四个缩略图img元素,我将它们添加到 jQuery Mobile 页面,并使用标准 CSS 来确保它们的大小都相同。我为tap事件创建一个处理程序(我在第二十七章中描述过),它将选定的图像设置为弹出窗口的内容,并调用open方法将其显示给用户(我在本章后面的使用弹出窗口方法一节中描述了 open 方法,但现在只要知道调用它将显示弹出窗口就足够了)。你可以在图 29-10 中看到效果:用户点击其中一个缩略图,一个更大的版本显示在弹出窗口中。
图 29-10 。使用弹出窗口显示图像
我混合使用了数据属性和设置来配置弹出窗口,只是为了展示两者的使用情况。弹出窗口下面的div元素具有data-history属性,如下所示:
...
<div id="popup" data-role="popup"data-history="true">
<img id="LgImage" class="zoomImg" src="" />
</div>
...
这是data-history属性的缺省值,但是我喜欢具体说明这个设置,因为它会引起很多混乱。我使用了script元素中的popup方法来设置其他选项,如下所示:
...
$("#popup").popup({
corners: false,
overlayTheme: "a"
});
...
使用圆角会裁剪掉大图的一部分,所以我使用corners设置来指定圆角。我想在弹出窗口显示时将用户的注意力集中在大图像上,所以我使用了overlayTheme设置来为弹出窗口提供深色背景。
当使用弹出窗口显示可能比弹出窗口本身更大的内容时,需要做一些额外的工作,因为默认情况下,内容会滚动。为了避免这种情况,我获取了窗口的高度,并将其作为设置弹出窗口中图像高度的基础,如下所示:
...
var maxHeight = $(window).height() - 10 + "px";
$("#LgImage").attr("src", e.target.src).css("max-height", maxHeight);
...
我让图像比窗口小 10 个像素,这给了我一个小边框来强调用户看到了一个弹出窗口。理论上,我应该将我的边框与tolerance设置对齐,但是在我写这个的时候这是不可靠的,所以我只是使用一个显式值来获得我想要的效果。我把序列中的第一个缩略图beach.png图像做得比其他的大,在图 29-11 中,你可以想象如果我不设置 CSS max-height属性的设置会发生什么:图像的顶部和底部不显示,也没有视觉提示指示用户可以滚动查看图像的其余部分。
图 29-11 。显示比弹出窗口大的内容的效果
使用弹出方法
弹出窗口小部件定义了表 29-8 中所示的方法。
表 29-8 。弹出方法
| 方法 | 描述 |
|---|---|
popup("open") | 打开弹出窗口。 |
popup("close") | 关闭弹出窗口。 |
popup("reposition") | 更改弹出窗口的位置。 |
我在前面的例子中演示了open方法的基本用法,但是您可以提供一个可选的参数来配置弹出窗口的打开方式,提供与用于a元素的data属性等效的功能。可选参数是一个对象,其属性名如表 29-9 所示。
表 29-9 。open 方法的可选参数的属性
| 名字 | 描述 |
|---|---|
x | 指定弹出窗口应该显示的 X 坐标。 |
y | 指定应显示弹出窗口的 Y 坐标。 |
transition | 指定用于动画弹出窗口的过渡–参见第二十八章了解 jQuery Mobile 过渡的详细信息。 |
positionTo | 使用表 29-6 中描述的值指定弹出窗口的位置。 |
reposition方法 也接受一个配置对象参数,您可以使用x、y,和positionTo属性来指定弹出窗口的新位置。close方法不接受任何参数,只是取消弹出窗口。在清单 29-13 中,你可以看到所有三种正在使用的方法。
清单 29-13 。使用弹出方法
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
<script>
$(document).bind("pageinit", function () {
$("button").bind("vmousedown", function (e) {
var pop = $("#popup");
switch (e.target.innerText) {
case "Open":
pop.popup("open", {
x: 10, y: 10, transition: "fade"
});
break;
case "Close":
pop.popup("close");
break;
default:
pop.popup("reposition", {
positionTo: e.target.innerText == "Window"
? "window" : "#page1 button"
});
break;
}
});
});
</script>
</head>
<body>
<div id="page1" data-role="page" data-theme="d">
<div data-role="content">
<button>Open</button>
</div>
<div id="popup" data-role="popup" data-history="true"
data-dismissible="false">
<button>Selector</button>
<button>Window</button>
<button>Close</button>
</div>
</div>
</body>
</html>
清单中的 jQuery Mobile 页面包含一个按钮,我通过调用弹出菜单上的open方法来处理该按钮的vmousedown事件。我传入可选的配置对象来指定弹出窗口应该显示在带有fade过渡的特定位置(x 轴和 y 轴上距离左上角 10 个像素)。
popup包含附加按钮。Close按钮调用close方法隐藏弹出窗口,其他按钮调用reposition方法指定弹出窗口应该移动到的不同位置。你可以在图 29-12 中看到结果。
图 29-12 。使用弹出方法
提示注意,在这个例子中,我已经将
data-dismissible属性设置为false。如果没有这个设置,大多数触摸浏览器产生的合成鼠标事件(如第二十七章所述)将被解释为弹出窗口之外的点击,导致弹出窗口在打开后立即关闭。将data-dismissible属性设置为false可以确保这种情况不会发生,并且弹出窗口只能被调用close方法的按钮关闭。
使用弹出事件
jQuery Mobile popup 小部件定义了表 29-10 中显示的事件。
表 29-10 。弹出事件
| 事件 | 描述 |
|---|---|
create | 创建弹出窗口小部件时触发。 |
beforeposition | 在弹出窗口重新定位之前触发。 |
afteropen | 弹出窗口显示后触发。 |
afterclose | 隐藏弹出窗口后触发。 |
我很少发现这些事件有用,我对弹出窗口小部件的使用通常仅限于方法和配置选项。一个例外是当我想在有限的时间内显示一个弹出窗口时,在这种情况下,afteropen事件会很有用,如清单 29-14 所示。
清单 29-14 。处理弹出事件
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jquery.mobile-1.3.1.css" type="text/css" />
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script>
$(document).bind("pageinit", function () {
$("#popup").popup({
afteropen: function (e) {
setTimeout(function () {
$("#popup").popup("close");
}, 5000);
}
});
});
</script>
<script type="text/javascript" src="jquery.mobile-1.3.1.js"></script>
</head>
<body>
<div id="page1" data-role="page">
<div data-role="header">
<h1>Jacqui's Shop</h1>
</div>
<div data-role="content">
<a href="#popup" data-rel="popup">Show the popup</a>
</div>
<div id="popup" data-role="popup" data-position-to="window">
<p>This is the popup content</p>
</div>
</div>
</body>
</html>
警告我只在无法与客户协商替代方案时使用这种技巧。我的感觉是,弹出窗口应该完全由用户控制,让它们以与用户交互没有直接联系的方式出现和消失会引起混乱。
在这个例子中,我处理afteropen方法调用setTimeout函数来注册一个将在五秒钟后执行的回调。回调函数调用close方法来关闭弹出窗口。
摘要
在本章中,我介绍了前两个 jQuery Mobile 小部件:对话框和弹出窗口。jQuery Mobile 小部件遵循与 jQuery UI 小部件相同的基本结构和原理,但是针对移动设备进行了明显的优化。在第三十章中,我描述了按钮和可折叠块部件。