jQuery Mobile 教程
一、 JQueryMobile 基础
1. jQuery Mobile 的渐进增强设计与浏览器支持 根据维基百科( Wikipedia ) 的解释,渐进增强的设计主要包括以下几点
?
basic content should be accessible to all web brow
sers (所有浏览器 都应能访问全部基础的内容)
?
basic functionality should be accessible to all web browsers (所有 浏览器都应能访问全部基础的功能)
?
sparse, semantic markup contains all content (所有的内容应该在少量 语义标签内)
?
enhanced layout is provided by externally linked CSS (增强的功能应 该由外部 CSS 提供)
?
enhanced behavior is provided by unobtrusive, externally linked JavaScript (增强的行为由外部 JavaScript 提供 )
?
end-user web browser preferences are respected (终端用户的浏览器习 惯应受尊重) 因为 jQuery Mobile 使用了渐进增强的设计理念,因而它所支持的系统与
平台也很广泛,能提供 A 级支持(支持全部的增强的体验,包括基于 Ajax 的 动画页面转场)的有以下平台:
Apple iOS 3.2-5.0 Android 2.1-2.3 , 3.1, 4.0 Windows Phone 7-7.5 Blackberry 6.0 , 7 Blackberry Playbook 1.0-2.0
1
Palm WebOS 1.4-2.0 , 3.0 Firebox Mobile (10 Beta) Skyfire 4.1 Opera Mobile 11.5 Meego 1.2 Samsung bada 2.0 Kindle 3 and Fire Nook Color 1.4.1 Chrome Desktop 11-17 Firefox Desktop 4-9 Internet Explorer 7-9 Opera Desktop 10-11
注: 若在实际的开发中使用到 Web SQL Database 等 HTML5 技术,则最终的 Web App 被支持度会比以上 jQuery Mobile 的被支持度低,但两个主流的移动浏览 器 Android 与 Apple iOS 的系统浏览器及其桌面版本肯定能提供最好的支持。 2. HTML5 data-* 属性 jQuery Mobile 依赖 HTML5 data-* 属性 来提供一系列的支持( UI 组件、过 渡和页面结构),不支持该 HTML5 属性的浏览器会默认忽略这些属性的效果, 比如在页面中添加一个版头,可以使用以下的 HTML:
<divdata-role="header"> <h1>jQueryMobileDemo</h1> </div>
这样就能产生一个 jQuery Mobile 样式的版头,从下文的图中可以看出, 这样的版头样式很适合移动设备使用, 并且在添加 data-role="header" 属性后,
2
div 内的 h1 也会被渲染成一定样式,这就是 jQuery Mobile 的方便快捷,也 是它的设计宗旨—— Write Less, Do More 。 除此之外 jQuery Mobile 中还有以下的 data-role 属性(部分属性),已 经赋予了一定的样式及用户操作响应效果。 data-role="content" , data-role="button" , data-theme ="" , data-role="controlgroup" , data-inline="true" , data-role="fieldcontain" , data-role="listview" , data-rel="dialog" , data-transition="pop" , 分别对应着主体内容、 按钮, 主题颜色, 已编辑按钮, 内联按钮,表单元素,列表视图,对话框,页面过渡。 3. jQuery Mobile 基本使用方法 3.1 引入 jQuery Mobile
使用 jQuery Mobile ,需要在网页页眉中引入 jQuery Mobile 组件,包括以下 部分
? ? ? jQuery 库 jQuery Mobile CSS jQuery Mobile 库
可以通过这样的 head 引入以上组件 Html 代码
<head> <title>jQuery Mobile Demo</title> <meta http-equiv="Content-Type" content="text/html; <meta name="viewport" <link rel="stylesheet" charset=UTF-8" /> content="width=device-width, initial-scale=1"> href=" /jquery.mobile-1.0.min.css" <script type="text/javascript" <script type="text/javascript" src=" jquery-1.6.4.min.js"></script> src=" /jquery.mobile-1.0.min.js"></script> </head> />
3
3.2
加入 viewport
在 Android 的浏览器中,若没有设定页面宽度,它会认为页面宽度是 980px , 因此我们可以在 head 里加入一个 viewport,让移动浏览器知道屏幕大小,只 是一个 viewport 标签,就已经给用户带来更好的体验。
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.5">
3.3
简单的页面实例
在引入 jQuery Mobile 需要的组件后,我们可以创建 jQuery Mobile 页面,下 面给出一个简单的例子。
Html 代码
<!DOCTYPE html> <html> <head> <title>jQuery Mobile Demo</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="" /> <script type="text/javascript" src=""></script> <script type="text/javascript" src=""></script> </head> <body> <div data-role="page" id="home"> <div data-role="header"> <h1>jQuery Mobile Demo</h1> </div> <div data-role="content"> <p>主体内容</p> </div> <div data-role="footer"> <h2>Footer</h2> </div> </div> </body> </html>
4
对于 jQuery Mobile ,每定义一个 data-role="page" 就相当于一个页面, jQuery Mobile 默认采用 Ajax 的方式操作 DOM,自动隐藏除第一个页面外的所 有页面,当点击链接,链接到其他页面时会以 Ajax 的方式加载新页面的内容, 下面给出完整实例。 另外, 我们还可以使用一些 HTML5 的语义化标签, 如 header 的 div 可以直接使用 header 标签,具体的可以参见下面的例子。
Html 代码
<!DOCTYPE html> <html> <head> <title>jQuery Mobile <meta <meta name="viewport" Demo</title> content="width=device-width, initial-scale=1"> /> http-equiv="Content-Type" content="text/html; charset=UTF-8" /> href=" /jquery.mobile-1.0.min.css" <script type="text/javascript" <script type="text/javascript" </head> <body> <div data-role="page" id="home"> Demo</h1> <header data-role="header"> <h1>jQuery Mobile </header> <div data-role="content"> <a </div> <footer data-role="footer"> <h2>Footer</h2> </footer> </div> <div data-role="page" id="page2"> Demo</h1> href="#page2" data-role="button">列表页面</a> src=" /jquery-1.6.4.min.js"></script> src=" /jquery.mobile-1.0.min.js"></script>
<link rel="stylesheet"
<header data-role="header"> <h1>jQuery Mobile </header> <div data-role="content"> <ul data-role="listview" <li><a <li><a <li><a data-inset="true"> href="#home">回到首页</a></li> href="#home">回到首页</a></li> href="#home">回到首页</a></li> 5
</ul> </div> <footer data-role="footer"> <h2>Footer</h2> </footer> </div> </body> </html>
完整实例 Demo(建议使用 PC 上的 Firefox、Chrome 等现代浏览器和 IE9+ 或 Android , iPhone/iPad 的系统浏览器浏览)
二、 jQuery Mobile 按钮
1. 一.Button 组件及 jQuery Mobile 如何丰富组件样式 在 jQuery Mobile 里,可以通过给任意链接添加 data-role=“button” 来产生一个 button 组件,jQuery Mobile 会追加一定的样式到链接,值得注意 的是,jQuery Mobile 在给组件元素追加样式时不一定只在原有的元素上添加
6
CSS 和 Javascript 响应, 一般还会追加一些新的元素使到组件的样式更接近于 原生的 App 组件样式。下面给出一个例子: 这是一个添加了 data-role=“button” 属性的链接,原 HTML 如下
Html 代码 <a href="#page2" data-role="button">Link button</a>
在浏览器上显示的样式如下:
这时用 DOM 查看工具查看实际得到的 HTML ,可以发现 jQuery Mobile 不仅给 原来的 a 元素添加了 CSS 以丰富按钮样式, 还另外追加了一些 HTML 使到样式 更加丰富,当然这个部分由 jQuery Mobile 自动完成,并不需要开发者操心太 多。
注:带链接的按钮元素和表单中的 button 元素会被自动渲染,无需另外添加 data-role="button" 属性。 2. 带图标按钮 jQuery Mobile 允许开发者通过在链接中添加 data-icon="" 属性来为 button 组件添加一个标准的 Web 图标, 并且支持通过 data-iconpos="" 属性设置图标 相对于文字的位置( top, bottom, right ,默认为 left )。
<a href="#page2" data-role="button" data-icon="check">Check</a>
7
<a href="#page2" eck</a>
data-role="button" data-icon="check" data-iconpos="top">Ch
data-icon 属性的可取值(来源于 jQuery Mobile 中文手册)
3. 按钮组
8
如果你希望把一些按钮放到一个容器内, 构建一个导航之类的独立部件 (按钮组) , 可以将按钮放到一个容器内并给容器设置 data-role="controlgroup" 属性, 如 果希望得到水平式的按钮组,则添加 data-type="horizontal" 属性到容器里。
<div data-role="controlgroup"> <a href="#page2" data-role="button">是</a> <a href="#page2" data-role="button">否</a> <a href="#page2" data-role="button">取消</a>
</div>
4. 其他按钮组件可用属性
1. data-theme=“” , 所有的 jQuery Mobile 组件均支持该属性, 用于设置组件的颜色, 该属性默认有五个值 a, b, c, d, e,分别代表由深到浅五种颜色,另外开发者还可以通过 在 CSS 里添加相应的 Class 来自定义颜色。
2. data-inline="" , 内联按钮, button 组件添加该属性后会自动改成内联的形式, jQuery Mobile 会给链接添加 display: inline-block 的 CSS ,让链接按照文字的长度来控制自 身长度,并且可以与其他内联元素共行。
三、 jQuery Mobile 表单
1. 表单组件基础
9
1.1
组件简介
jQuery Mobile 中的表单组件是基于标准 HTML ,然后在此基础上增强样式,因 此即使浏览器不支持 jQuery Mobile 表单仍可正常使用。需要注意的是, jQuery Mobile 会把表单元素增强为触摸设备很容易使用的形式,因此对于 iphone/ipad 与 Android 使用 Web 表单将会变得非常方便。
jQuery Mobile 的表单组件有以下几种:
?
文本输入框, type="text" 标记的 input 元素会自动增强为 jQuery Mobile
样式,无需额外添加 data-role 属性。
?
文本输入域, textarea 元素会被自动增强,无需额外添加 data-role 属性,
用于多行输入文本,jQuery Mobile 会自动增大文本域的高度,避免在移动设备 中很难找到滚动条的情况。
?
搜索输入框, type="search" 标记的 input 元素会自动增强,无需额外添加
data-role 属性, 这是一个新的 HTML 元素, 增强后的输入框左边有一个放大镜 图标,点击触发搜索,在输入内容后,输入框的右边还会出现一个叉的图标,点 击清除已输入的内容,非常方便。
?
单选按钮, type="radio" 标记的 input 元素会自动增强,无需额外添加
data-role 属性。
?
复选按钮, type="checkbox" 标记的 input 元素会自动增强,无需额外添加
data-role 属性。
? ?
选择列表, select 元素会被自动增强,无需额外添加 data-role 属性。 划杆, type="range" 标记的 input 元素会自动增强,无需额外添加
data-role 属性。
?
开关, select 元素添·加 data-role="slider" 属性后会被增强会 jQuery
Mobile 的开关组件, select 中只能有两个 option。
1.2
组件使用规范
所有的表单组件,只要是需要与服务器传送数据,都应该包裹在一个 form 标签内,并 且应该指定好 form 的 action 和 method 属性。当然如果你使用的是 Web SQL
10
Database 这类本地储存,即数据并不需要与服务器传送,可以不用 form 标签和 sumbit 提交。 另外 form 的 id 需要在整站中唯一, 由于 jQuery Mobile 使用 Ajax 导 航,因此不同的 page 可以同时加载到一个 DOM 中,因此 form id 必须整站唯一以保 证每个 DOM 的表单 id 都是不同的。 每一个表单元素应该要有相应的 label 对应,label 的 for 值要与元素的 id 相 同,使其在语义上相关,并且可以使用一个带有 data-role="fieldcontain" 属性的 div 或 fieldset 容器包裹, jQuery Mobile 会自动在容器底部增加一条细边框作为 分隔。
2. 表单组件详解 2.1 文本输入框
在 jQuery Mobile 中,文本输入框和文本输入域都是使用标准 HTML 标记的,并且支 持一些 HTML5 的 input 类型,如 password, email, tel, number, range 等更多的 类型,而对于一些类型( range, serach ) jQuery Mobile 则会将其转换为 text 的 input 类型,统一标准化其样式,下面是文本输入框的调用代码及示图。
<div data-role="fieldcontain"> <label for="text">文本输入框</label> <input type="text" name="text" id="text" value=""
/>
</div>
2.2
<div
文本输入域
data-role="fieldcontain"> <label for="textarea">文本输入域</label> <textarea cols="40" rows="8" name="textarea" id="textarea"></textarea>
</div>
11
2.3
搜索输入框
正如上文所述, 增强后的输入框左边有一个放大镜图标, 点击触发搜索, 在输入内容后, 输入框的右边还会出现一个叉的图标,点击清除已输入的内容。
<div data-role="fieldcontain"> <label for="search">搜索输入框</label> <input type="search" name="search" id="search" value="" />
</div>
2.4
单选框
单选框组件用于在页面中提供一组选项, 并且只能选择其中一个选项。 在 jQuery Mobile 中,单选框组件不但在外观上美化了,还增加了一些图标用于增强视觉反馈。 type="radio" 标记的 input 元素会自动增强为单选框组件,但 jQuery Mobile 建议 开发者使用一个带 data-role="controlgroup" 属性的 fieldset 标签包括选项, 并且 在 fieldset 内增加一个 legend 元素,用于表示该单选框的标题。
<div data-role="fieldcontain"> <fieldset data-role="controlgroup"> <legend>单选框:</legend> <input type="radio" name="radio-choice-1" id="radio-choice-1" value="choice-1" /> <label for="radio-choice-1">蓝</label> <input type="radio" name="radio-choice-1" id="radio-choice-2" value="choice-2" /> <label for="radio-choice-2">绿</label> <input type="radio" name="radio-choice-1" id="radio-choice-3" value="choice-3" /> <label for="radio-choice-3">黑</label>
12
</fieldset> </div>
2.5
复选框
复选框也是用于在页面中提供一组选项的,但可以同时选择多个选项。与单选框相同, 复选框组件也无需额外调用 data-role 属性, type="checkbox" 标记的 input 元素 会自动增强为 jQuery Mobile 样式,当然 jQuery Mobile 也建议开发者使用一个带 data-role="controlgroup" 属性的 fieldset 标签包括选项,并且在 fieldset 内增 加一个 legend 元素,用于表示该复选框的标题。
<div data-role="fieldcontain"> <fieldset data-role="controlgroup"> <legend>复选框</legend> <input type="checkbox" name="blue" id="effect1" class="custom" /> <label for="effect1">效果 1</label> <input type="checkbox" name="green" id="effect2" class="custom" /> <label for="effect2">效果 2</label> <input type="checkbox" name="pink" id="effect2" class="custom" /> <label for="effect2">效果 3</label> </fieldset>
</div>
默认的复选框组件是垂直排列选项的,我们可以在 fieldset 上添加 data-type="horizontal" 使其样式改为水平按钮组的样式, jQuery Mobile 会使选项 元素浮动并去掉图标。
13
2.6
选择列表
选择列表是基于 HTML select 元素的,具有原生菜单和自定义菜单两种形式,原 生菜单与自定义菜单都有一个样式美化了的选择按钮, 不同的是在自定义菜单中原生的 option 元素将被隐藏, jQuery Mobile 会生成一个由 CSS3 和 HTML5 构成的菜单代 替,并且这个菜单是 ARIA 的。 关于 ARIA , 这里小科普一下: ARIA, 即 Accessible Rich Internet Application ( 加强无障碍网页应用程序 ),它是 W3C 的无障碍网页倡议(WAI)工作小组在倡导 大家使用的无障碍网页应用技术。它是一套独立的规范,可以帮助 Web 程序,尤其是 使运用了大量前端技巧( Ajax )的网页更具备可访问性,通俗点说,读屏设备等不大 能理解前端语义的设备将可以了解到页面的内容, 这样残疾人士不仅可以浏览网页甚至 与页面进行交互。 HTML select 元素会被自动增强为原生的选择列表组件,若需要自定义样式菜单, 可以在 select 上添加 data-native-menu="false" 属性。 若需要禁止选择某一个选项, 可以在选项的 option 标签上添加 disabled="disabled"。 下面给出一个自定义菜单的例子:
<div data-role="fieldcontain"> <label for="select-choice-1" class="select">选择列表</label> <select data-native-menu="false" name="select-choice-1" id="select-choice-1"> <option value="12h">12 小时</option> <option value="1d">一天</option> <option value="2d">两天</option> <option value="week">一周</option> </select>
</div> 选择按钮
14
自定义菜单
若需要多项选择,则可以在 select 标签上添加 multiple="multiple" ,但原生的选 择菜单不支持该功能。对于多项选择菜单,还有几点要注意的:
?
jQuery Mobile 会在菜单里创建一个 jQuery Mobile header ,并在 header 的 左边添加一个关闭菜单按钮。
?
当用户选择两个或以上选项时选择按钮右侧会出现一个小图标,图标内显示已 选择选项的个数。
?
所有选择的选项文本会显示在选择按钮上,如果文字超出按钮长度,会以省略 号代替多余的内容。
?
如果选项过多,菜单会以新页面的形式显示。
多项选择列表实例
<div data-role="fieldcontain"> <label for="select-choice-2" class="select">多项选择列表 </label> <select data-native-menu="false" multiple="multiple" name="select-choice-2" id="select-choice-2"> <option value="12h">12 小时</option> <option value="1d">一天</option> <option value="2d">两天</option> <option value="week">一周</option> </select> </div>
15
另外我们还可以对选项进行分组,使用以下标签标签把同一组的选项包裹起来,其中 label 的值为该分组的标题。
<optgroup label="Group1"></optgroup>
分组选择列表实例 <div data-role="fieldcontain"> <label for="select-choice-3" class="select">分组选择列表</label> <select data-native-menu="false" name="select-choice-3" id="select-choice-3"> <optgroup label="Group1"> <option value="12h">12 小时</option> <option value="1d">一天</option> <option value="2d">两天</option> <option value="week">一周</option> </optgroup> <optgroup label="Group2"> <option value="1m">一个月</option> <option value="1q">一季度</option> <option value="1y">一年</option> </optgroup> </select> </div>
16
2.7
滑杆
在 jQuery Mobile 中,type="range" ( HTML5 属性值 ) 的 input 元素会被增强为 划杆组件, 该组件可以通过一些属性值配置, value 设置滑杆的初始值, min 和 max 分 别设置滑杆的下限和上限。 另外滑杆组件还支持键盘响应, 键盘的右箭头, 上箭头, Page Up 键都可以增加滑杆的当前值,相应的,左键头,下箭头, Page Down 键可以减少滑 杆的当前值,使用 Home 键和 End 键则可以设置当前值为最小值(下限)和最大值(上 限)。
<div data-role="fieldcontain"> <label for="slider">滑杆</label> <input type="range" name="slider" id="slider" value="0" min="0" max="100"
/>
</div>
17
2.8
开关
具有两个 option 的 select 元素添加 data-role="slider" 属性后会被增强为 jQuery Mobile 的开关组件,用于表示布尔型数据( ture or false ),拖动滑动条 可以在“开”与“关”之间选择,其中第一个 option 会被渲染成“开”的样式。
<div data-role="fieldcontain"> <label for="slider">开关</label> <select name="slider" id="slider" data-role="slider"> <option value="off">关闭</option> <option value="on">开启</option> </select>
</div>
3. 提交表单
jQuery Mobile 自动采用 Ajax 的方式提交表单,默认的 method 为 get ,action 为 当前页面的相对路径,在表单页面和结果页面之间会有平滑的转场过渡,并且可以在表 单上使用 data-transition 指定转场效果。如果不想使用 Ajax 的方式提交表单,可 以在全局事件禁用 Ajax (如何全局禁止 Ajax 并不在本文讨论范围,但会在本系列的 后续文章中作详细说明)或是在 form 上添加 data-ajax="false" 属性,下面是 data-transition 的所有可取值。 slide 滑动 (默认值, 从左至右滑出) , slideup (从 下至上滑出), slidedown(从上至下滑出), pop(从中心渐显展开), fade(渐 显), flip(翻转)。
4. 主题样式
关于主题样式,在上一文中已经介绍过了,这里引用一下:data-theme=“” 属性, 所 有的 jQuery Mobile 组件均支持该属性,用于设置组件的颜色, 该属性默认有五个值 a, b, c, d, e,分别代表由深到浅五种颜色,另外开发者还可以通过在 CSS 里添加相 应的 Class 来自定义颜色。”
5. 刷新表单组件
18
由于 jQuery Mobile 对原生的 HTML 表单元素进行了渲染和追加元素,所以开发者想 通过 js 直接控制表单组件会比较麻烦(如使用了 Web SQL Database 储存了数据在本 地,在打开网页时希望通过 js 获取数据并给表单组件赋值的情况),因此 jQuery Mobile 设计了用 js 给表单组件赋值的 API ,下面逐一举例介绍:
5.1
单选按钮
选择第一个选项 $("input[type='radio']:first").attr("checked",true).checkboxradio("refresh");
5.2
复选按钮
选择第一个选项 $("input[type='checkbox']:first").attr("checked",true).checkboxradio("refresh")
5.3
选择列表
选择第一个选项,注意选项的索引是从 1 开始 var myselect = $('select#select-choice-1'); myselect[0].selectedIndex = 1; myselect.selectmenu('refresh');
5.4
滑杆
设置值为 40 $("input[type=range]").val(40).slider("refresh");
5.5
开关
选择第一个选项 var myswitch = $('select#shakeToClear'); myswitch[0].selectedIndex = 1; myswitch.slider('refresh');
19
注: refresh 方法不能直接使用在 Ajax 获取的内容上,例如 js 要操纵的表单组件在另 一个 Page, js 只在首页加载时载入,这样 jQuery Mobile 会出错(不会有直接报错,只 是该段 js 会失效),我们可以使用 live('pagebeforeshow', function(){}) 方法使到该 段 js 在过场到表单组件所在页面时才载入( pagebeforeshow 是 jQuery Mobile 事件之 一,此外还有 pagebeforehide, pageshow, pagehide 三种方法)。下面给出一个例子: $('#setting').live('pagebeforeshow', function(){ // 在页面显示时选择菜单中第一个选项 var myselect = $('select#select-choice-1'); myselect[0].selectedIndex = 1; myselect.selectmenu('refresh'); });
四、 jQuery Mobile 内容格式
1. 基本 HTML 样式(Basic HTML styles)
jQuery Mobile 会对默认的 HTML 渲染进行样式丰富, Kayo 曾经在之前的文章中以 button 组件为例子介绍过 jQuery Mobile 样式丰富的方法,各位可以参考前文中的第 一部分—— Button 组件及 jQuery Mobile 如何丰富组件样式 , 来了解 jQuery Mobile 基本 HTML 样式的丰富方法。
2. 主题内容(Theming content)
有看过 Kayo 之前所写的文章的童鞋应该对主题内容不陌生了,所有的 jQuery Mobile 组件均支持通过添加 "data-theme=" 属性来为组件添加颜色主题, 该属性默认 有五个值 a, b, c, d, e,分别代表由深到浅五种颜色,另外开发者还可以通过在 CSS 里添加相应的 Class 来自定义颜色。 需要自定义主题颜色的童鞋可以编辑 jquery.mobile-1.1.0 文件,在文件中模仿 a, b, c, d, e 默认样式的 css 写出自定义的颜色,值得一提的是, jQuery Mobile 的 主题颜色是使用 CSS3 的渐变颜色,因此直接写出自己的颜色比较困难,建议大家使用 jQuery Mobile 官方的主题编辑器,可以很方便的创建自定义的主题。
3. 可折叠内容块(Collapsible content blocks)
20
在 jQuery Mobile 里,可以通过给容器添加 data-role="collapsible" 来产生一个可 折叠内容块组件,通常容器中需要类似如下类型的结构:
<div data-role="collapsible"> <h3>标题部分</h3> <p>主体内容部分,默认会在本页折叠</p> </div> 效果如下:
另外在新版的可折叠内容块组件中,可折叠块默认是收缩起来的,点击标题展开内容, 再次点击则重新折叠内容,开发者可以通过给可折叠内容块的容器添加 data-collapsed="false" 属性使折叠块默认为展开的。 可折叠内容块组件支持嵌套使用:
<div data-role="collapsible"> <h3>标题部分</h3> <div data-role="collapsible"> <h3>标题部分</h3> <p>主体内容部分,默认会在本页折叠</p> </div> </div>
21
4. 折叠组(Collapsible sets)
把若干个可折叠内容块组件用一容器包裹,并给包裹添加 data-role="collapsible-set" 属性,即为折叠组组件。 jQuery Mobile 会把这些可 折叠内容块在样式上整合为一个整体,产生类似于手风琴的效果(每次只会展开一个子 元素)。
假如 HTML 代码如下: <div data-role="collapsible-set"> <div data-role="collapsible" data-collapsed="false"> <h3>第一部分</h3> <p>第一部分主体内容</p> </div> <div data-role="collapsible"> <h3>第二部分</h3> <p>第二部分主体内容<</p> </div> <div data-role="collapsible"> <h3>第三部分</h3> <p>第三部分主体内容</p> </div> </div> 得到如下如所示的效果
22
5. 网格布局(Layout grids)
为了能创建比较复杂的布局 (两列布局 (class 中含有 ui-grid-a) 和三列布局 (class 中含有 ui-grid-b)), jQuery Mobile 利用 CSS 创建了两种预设的配置布局。
5.1
两栏布局
要创建两栏布局,可以先给父元素添加 ui-grid-a 的 class ,然后分别为第一个子元 素添加 ui-block-a 的 class , 第二个子元素添加 ui-block-b 的 class ,具体例 子如下:
<div class="ui-grid-a"> <div class="ui-block-a">第一个子元素 Block A</div> <div class="ui-block-b">第二个子元素 Block B</div> </div> 效果如下图:
另外网格布局也可用于 jQuery Mobile 组件中,如下的 HTML: <fieldset class="ui-grid-a"> <div class="ui-block-a"><button type="submit" data-theme="e">Cancel</button></div> <div class="ui-block-b"><button type="submit" data-theme="b">Submit</button></div> </fieldset>
23
效果如下:
5.2
多栏布局
要创建三栏布局, 可以先给父元素添加 ui-grid-b 的 class , 然后分别为第一个子元 素添加 ui-block-a 的 class , 第二个元素添加 ui-block-b 的 class ,第三个元素添 加 ui-block-c 的 class 。以此类推,四栏布局使用 ui-grid-c 的 class ,五栏布局使 用 ui-grid-d 的 class 。
五、 jQuery Mobile 列表
1. 基本的列表
要使用 jQuery Mobile 的列表组件非常简单,只要在 ul, ol 中使用 data-role="listview" 属性即可。 1. <ul data-role="listview"> 2. <li><a href="#">列表项 A</a></li> 3. <li><a href="#">列表项 B</a></li> 4. </ul>
上面的代码即可生成一个简单的 jQuery Mobile 列表,效果如下图所示(若是有序列 表 ol ,则在列表项前会显示对应的序号),另外列表项中若带有链接,则会在列表项 中添加一个向右的小箭头。
24
2. 嵌套的列表
在 ul, ol 中再次嵌入 ul, ol 可以生成嵌套列表,例如下面代码所生成的即为嵌套列表 <ul data-role="listview"> <li>老师 <ul> <li><a <li><a </ul> </li> <li>学生 <ul> <li><a <li><a </ul> </li>
href="#home">老师 A</a></li> href="#home">老师 B</a></li>
href="#home">学生 A</a></li> href="#home">学生 B</a></li>
</ul> 效果如下:
jQuery Mobile 会以最高级的列表项内容生成列表,点击某列表项后会生成一个新的页 面,该页面以被点击项的文字内容生成一个 header ,并显示子列表内容。具体的效果 可以参见文章底部的 demo 。
3. 只读列表
25
上面的例子中,列表项都是带链接的,其实 jQuery Mobile 也支持不带链接的列表, 较为常用的是在嵌套列表中嵌入一个不带链接的列表, 这种列表称为只读列表, jQuery Mobile 默认将列表样式设置为 “c” 主题样式(纯白无渐变),并把字体字号设置成 比可点击的列表较小,以减小列表项大小。
1. <ul data-role="listview"> 2. <li>列表项 A</li> 3. <li>列表项 B</li> 4. </ul>
4. 列表项的缩略图与图标
jQuery Mobile 列表支持在列表项左侧加入一幅图片,只要在 li 标签中添加一幅图片 并且作为第一子元素即可,图片大小没有限制, jQuery Mobile 会自动把图片大小缩 放为 80px 的正方形 (当然实际上所用的图片最好本身大小为 80px 的正方形) 。 例如, 为一个移动版的论坛制作评论列表,正好适合使用这种结构,这时列表项的缩略图是评 论者的头像。
<ul data-role="listview" data-split-icon="delete"> <li> <img src="images/album-hc.jpg" /> <h3>Reviewer A</h3> <p>jQuery Mobile 很方便的把这类结构<p> </li> <li> <img src="images/album-p.jpg" /> <h3>Reviewer B</h3> <p>jQuery Mobile 很方便的把这类结构调整为你看到的</p> </li> <li> <img src="images/album-ok.jpg" /> <h3>Reviewer B</h3> <p>jQuery Mobile 很方便的把这类结构调整为你看到的这</p>
26
</li> </ul> 则有如下效果:
5. 侧分列表
上面的基本例子中,因为列表项中带有链接,所以点击链接能触发一个事件,若实际的 项目中需要一个列表项带有两个操作,则需要另一种结构的列表,也就 是侧分列表。 这时习惯 PC Web 前端开发的开发者可能会觉得有点奇怪,为什么一个列表项需要多个 操作交互,实际上列表这种结构在 Web App 类网页中具有很多方面的用途,而不是只 作为简单的信息呈现。比如上面的“评论列表”示例, 我们可以在每条评论的右侧添 加一个删除评论按钮,这时则需要两个交互按钮——点击左侧为打开评论者链接(评论 者主页),点击右侧删除评论。 jQuery Mobile 为这种结构提供了一种很方便的处理 方式——在 li (或 ol)中加入第二个链接, jQuery Mobile 会创建一个竖直的分割 线把第二个链接分隔开。
如下面的 HTML 结构: <ul data-role="listview" data-split-icon="delete"> <li> <a href="#page2"> <img src="images/album-hc.jpg" /> <h3>Reviewer A</h3> <p>jQuery Mobile 很方便的把这类结构调整为你看到的样式</p>
27
</a> <a href="#" data-rel="dialog">Delete</a> </li> <li> <a
href="#page2"> <img src="images/album-p.jpg" /> <h3>Reviewer B</h3> <p>jQuery Mobile 很方便的把这类结构调整为你看到的这个样式</p> </a> <a href="#" data-rel="dialog">Delete</a> </li> <li> <a href="#page2"> <img src="images/album-ok.jpg" /> <h3>Reviewer C</h3> <p>jQuery Mobile 很方便的把这类结构调整为你看到的这个样式</p> </a> <a href="#" data-rel="dialog">Delete</a> </li> </ul> 则有如下效果:
如效果图所示, jQuery Mobile 会把两个链接的内容以竖直分割线分开,并且第二个 链接的文字内容会隐藏起来,以一个标准 Web 按钮代替,标准 Web 按钮的样式可以在 ul 标签上添加 data-split-icon 属性指定, 可取值可以参考《使用 jQuery Mobile 与 HTML5 开发 Web App —— jQuery Mobile 按钮》第二部分“带图标按钮” 中
28
data-icon 的可取值。另外该按钮的主题样式可以通过在 ul 或 ol 标签上添加 data-split-theme 属性指定,默认为"b"(蓝)。
6. 分割列表
分割列表从效果上来看是一种分组列表,而在 HTML 结构上,它与基本列表相同,只是 通过 data-role="list-divider" 属性把基本列表转化为分割列表, 貌似有点复杂?其 实看了下面的代码和效果图就会一目了然。
<ul data-role="listview"> <li data-role="list-divider">老师</li> <li><a href="#page2">老师 A</a></li> <li><a href="#page2">老师 B</a></li> <li data-role="list-divider">学生</li> <li><a href="#page2">学生 A</a></li> <li><a href="#page2">学生 B</a></li>
</ul>
默认情况下分割列表的主题样式为"b"(蓝),开发者可以通过在 ul 或 ol 标签上添 加 data-split-theme 属性指定主题样式。
7. 搜索过滤框
jQuery Mobile 给开发者提供了一种简便的过滤列表方式,若需要过滤列表只需在 ul 或 ol 标签上添加 data-filter="true" 属性即可。 jQuery Mobile 会自动在列表顶
29
部添加一个搜索框,当用户在搜索框中输入字符时, jQuery Mobile 会自动过滤掉不 包含这些字符的列表项。值得注意的是,这个过滤是 Ajax 模式的过滤方式,它不需要 等待整个输入完成才开始过滤,每当用户输入字符时, jQuery Mobile 会即时过滤掉 不包含这些字符的列表项。
1. <ul data-role="listview" data-filter="true"> 2. <li><a href="#page2">你</a></li> 3. <li><a href="#page2">你好</a></li> 4. <li><a href="#page2">你好啊</a></li> 5. </ul>
8. 其他
jQuery Mobile 支持通过使用语义化的标签来显示列表项中一些常用的信息,如上面的 “列表项的缩略图与图标”和“侧分列表”中, 列表项中除了描述外还有标题, jQuery Mobile 会按照标题的标签语义处理成不同的文字样式,这里 Kayo 再以“评论列表” 示例进行拓展说明。如下的代码:
<ul data-role="listview" data-split-icon="delete"> <li data-role="list-divider"> 评论列表<span class="ui-li-count">3</span> </li> <li> <img src="images/album-hc.jpg" /> <h3><a href="#page2">Reviewer A</a></h3> <p>jQuery Mobile 很方便的把这类结构调整为你看到的这个样式</p>
30
<p </li> <li>
class="ui-li-aside">2012-02-25 21:37</p>
<img src="images/album-p.jpg" /> <h3><a href="#page2">Reviewer B</a></h3> <p>jQuery Mobile 很方便的把这类结构调整为你看到的这个样式</p> <p class="ui-li-aside">2012-02-25 21:45</p> </li> <li> <img src="images/album-ok.jpg" /> <h3><a href="#page2">Reviewer B</a></h3> <p>jQuery Mobile 很方便的把这类结构调整为你看到的这个样式</p> <p class="ui-li-aside">2012-02-26 11:55</p> </li> </ul> 效果图:
备注: 这个例子中, Kayo 把评论中的“删除”按钮舍弃,改为显示评论时间,这时的评论列 表更接近于博客的评论列表, 以 h3 标签包含评论者名称, 表示对评论者的强调, p 标 签则包含评论内容,并且把评论者的链接(评论者主页)从侧分列表中的整个左侧都带 链接改为只是评论者名称带链接。下面再具体说明一下:
31
?
使用容器包裹数字,为该容器添加 ui-li-count 的 class 并添加到列表项中, jQuery Mobile 会自动为该容器添加气泡样式用于表示计数。
?
在语义上层次不同的文本 jQuery Mobile 会以不同大小,粗细的字体显示该段 文字,以表示文字重要性的不同。
?
补充信息可以用 class 为 ui-li-aside 的容器包裹并放在列表项的下方 (如示 例中的评论日期), jQuery Mobile 会自动把它呈现在列表项的右侧(这时不 能使用侧分列表,因为侧分列表右侧需要显示列表项中的第二个链接)。
六、 jQuery Mobile 工具栏
1. 工具栏基础
在 jQuery Mobile 中,有两套标准工具栏——头部栏和尾部栏,头部栏通常是放 在网页顶部,而尾部栏通常放在网站底部,值得注意的是,头部栏和尾部栏的位置并不 依靠 CSS 和 JavaScript 定位,而是本身就处于文档流的顶部或底部,这样是为了尽 量保证那些对于 CSS 和 JavaScript 支持并不好的设备也可以看到工具栏,另外也不 用消耗多余的 CSS 和 JavaScript 资源。 可能在阅读上面这段话后,童鞋们可能有点迷惑,没关系,下面会分开介绍这些属 性,相信阅读后便会理解 jQuery Mobile 的工具栏组件了。
2. 头部栏
头部栏正如其名字所表达的,是处于页面头部的栏目,使用 data-role="header" 属性可以产生头部栏。除了表示标题的文字外,在头部栏的左边或右边可以放置几个可 选的按钮,作为导航之用(返回上一页,回到首页等)。使用 h1 的 HTML 标签包裹文 字,这段文字会被解释为标题文字,赋予相关的样式,而在 h1 标签的上下文中,可以 通过使用按钮标记放置按钮, 其中在 h1 标签上的按钮会被放置在头部栏左边, 而在 h1 标签之下的按钮会被放置在头部栏右边。
32
如上面描述,在 h1 标签的上下文中,可以通过使用按钮标记放置按钮,通常自定 义的按钮会使用 a 标签,给标签添加 data-rel="back" 属性会自动生成后退按钮,点 击后退按钮返回的是历史记录中的上一个页面,而无视该 a 标签的 href 属性值,但 是对于 C 级浏览器,情况刚好相反, C 级浏览器只会识别 href 属性值,而不会直接 退回历史记录中的上一个页面,因此要设计一个良好的导航,也必须根据实际情况给 href 设定一个有意义的值,而提高 C 级浏览器的用户体验。除此之外,开发者还可以 使用 data-icon 属性改变按钮上的 icon 小图标,而 data-icon 的可取值可以参考 《使用 jQuery Mobile 与 HTML5 开发 Web App —— jQuery Mobile 按钮》中的“带 图标按钮”。
下面给出一个带有两个按钮的例子: Html 代码
1. <div 2. 3. 4. 5. </div> data-role="header"> <a <a data-rel="back" href="#home" data-icon="delete">取消</a> <h1>常见头部栏</h1> href="#home" data-icon="check">保存</a>
效果:
这里必须强调一下, 例子中的链接的 href 值为 "#home", 这是 jQuery Mobile 所 支持的一种链接, "home" 指是一个 jQuery Mobile page 的 id 值,使用这种写法可 以很方便的链接到该 page ,参考文章底部 Demo 的源码可以看到完整的代码。 另外开发者也可以使用 CSS class 来控制按钮的位置:ui-btn-left 和 ui-btn-right class 分别是控制按钮在头部栏的左边和右边,并且设置相应的 class 后,按钮的位置只根据类来分配,与它们实际在 HTML 源码中的位置无关。
1. <div 2. 3. 4. <h1>使用 CSS <a data-role="header"> class= "ui-btn-right" href="#home" data-rel="back" data-icon="delete">取消</a> 类控制按钮位置的自定义头部栏</h1> 33
5.
<a
class="ui-btn-left" href="#home"
data-icon="check">保存</a>
6. </div>
效果:
3. 尾部栏
在 jQuery Mobile 中,使用 data-role="footer" 可以产生尾部栏,尾部栏的情 况跟头部栏基本相同,也支持放置按钮,通过 CSS 类调整按钮位置,这里给出一个基 本的尾部栏例子:
1. <footer 2. data-role="footer"> <h2>Demo By <a href="" none; ">Kayo</a></h2> target="_blank"
3. style="text-decoration: 4. </footer>
效果:
另外在尾部栏中添加一个按钮组可以很方便的做出一个工具栏, 关于按钮组的使用可以参见 《使用 jQuery Mobile 与 HTML5 开发 Web App —— jQuery Mobile 按钮》 中的“按钮组” 部分。
4. 导航栏
导航栏可以为开发者提供一种简便的导航菜单方案,首先给出一个例子:
1. <div 2. 3. 4. 5. 6. 7. 8. 9. </div> </div> data-role="header"> data-role="navbar"> <li><a <li><a <li><a </ul> href="#" class="ui-btn-active">One</a></li> <ul> href="#">Two</a></li> href="#">Three</a></li>
<div
34
这里说明一下, 导航栏并不一定需要头部栏包裹, 不过一般建议放在头部栏或尾部栏中。 要设置某一个链接为活动状态(当前状态),可以给该链接添加 "ui-btn-active" 的 class ,如例子中设置了第一个链接为当前活动状态。
5. 固定位置的工具栏与全屏的工具栏
我们可以给工具栏添加 data-position="fixed" 的属性,这样工具栏就会固定在 页面中,并不随页面滚动而滚动了,当工具栏滚出屏幕后,可以通过点击屏幕使其再次 出现。在此基础上,若再为工具栏添加 data-fullscreen="true" 属性,则能触发工具 栏全屏模式, 这样页面的主体内容会占满页面, 然后通过点击屏幕使工具栏出现或消失。 也许你会觉得这个情景很熟悉,的确,这种方式在一些 App 上很常见,比如视频网站 的 App ,播放视频时显示进度条,音量按钮,清晰度选择等,点击屏幕工具条就会消 失,需要时再次点击就会出现。现在这样的功能 Web App 也做到了,并且很简便,配 合出 HTML5 的一些属性,也就能方便的做出一些很酷的 Web App!
固定位置的工具栏
1. <div 2. 3. data-role="header" data-position="fixed"> <a href="#home" data-rel="back" data-icon="delete">取消</a> <h1>固定位置的工具栏</h1>
4. </div> 固定位置的全屏工具栏
1. <div 2. 3. data-role="header" data-position="fixed" data-fullscreen="true"> <a href="#home" data-rel="back" data-icon="delete">取消</a> <h1>固定位置的工具栏</h1>
4. </div> 由于这里要显示的效果是动态的, 就不放效果图了, 建议大家直接查看完整 Demo 中相应的 例子, 其中“固定位置的全屏工具栏”在 PC 会出现相滚动条的情况, 建议使用移动浏览器 查看。
6. 主题样式
与其他 jQuery Mobile 组件一样,工具栏也是支持使用主题样式的,可以使用 data-theme 属性在组件的标签上添加主题样式,该属性默认有五个值 a, b, c, d, e,
35
分别代表由深到浅五种颜色, 另外开发者还可以通过在 CSS 里添加相应的 class 来自 定义颜色,而默认的样式则为 a ,即黑色。
七、 jQuery Mobile 页面与对话框
1. 页面基础
在 jQuery Mobile 中,页面这个概念与传统的 Web 页面有一个很大的区别 —— jQuery Mobile 中的页面可以是单个的页面,也可以是一个页面中内嵌多个 "Page" , “Page” 是 jQuery Mobile 中的页面,下面将会为大家详细介绍它。 Page 是 jQuery Mobile 的重要组成部分,由 data-role="page" 属性产生,每个 Page 由之前介绍过的 header , content , footer 组成,但这些元素并不是必须的, 不过一个完整的页面最好同时都有这些元素。下面举一个例子,这也是《使用 jQuery Mobile 与 HTML5 开发 Web App —— jQuery Mobile 基础》中的例子,为了方便大家 阅读,这里重新例举一次。
1. <!DOCTYPE html> 2. <html> 3. <head> 4. 5. 6. 7. 9. 11. 13. </head> 14. <body> 15. 16. <div 17. 18. 19. 20. 21. </div> <div data-role="content"> <p>主体内容</p> 36 data-role="page" <div id="home"> Demo</h1> data-role="header"> <h1>jQuery Mobile <title>jQuery Mobile <meta <meta <link Demo</title> initial-scale=1"> http-equiv="Content-Type" content="text/html; charset=UTF-8" /> name="viewport" content="width=device-width, rel="stylesheet" href=" src=" src="
8. /jquery.mobile-1.0.min.css" /> <script type="text/javascript" <script type="text/javascript" 10. /jquery-1.6.4.min.js"></script> 12. /mobile/1.0/jquery.mobile-1.0.min.js"></script>
22. 23. 24. 25. 26. </div> 27. </body> 28. </html>
</div> <div data-role="footer"> <h2>Footer</h2> </div>
效果:
下面说明一下:
jQuery Mobile 网站必须使用 HTML5 的文档声明,使得这个网站能适用 HTML5 的 特性,不支持这些特性的浏览器会安全地静默忽略 HTML5 的文档声明和一些属性。 HTML5 文档声明:
1. <!DOCTYPE html>
在页面 head 内,使用了 viewport 的 meta 标签控制了页面的缩放,例子中的 width=device- width, initial-scale=1 即控制页面宽度等于屏幕宽度,页面缩放比 例为 1 ,这样浏览器就不会随意缩放页面了。
2. 多页面结构
37
如上面所说,一个页面中可以内嵌多个 Page ,每个 Page 需要一个 ID 标记,页 面间通过 “#ID” 的链接方式跳转, 除第一个 Page 外, 其他 Page 会使用隐藏起来, 当链接被点击时, jQuery Mobile 会跳转到相应的 Page ,这个过程会以 Ajax 的方 式完成,把新页面的内容加载到 DOM 中。下面是一个多页面结构的代码参考:
1. <!DOCTYPE html> 2. <html> 3. <head> 4. 5. 6. 7. 8. 9. 10. </head> 11. 12. <body> 13. <div 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. </div> 27. 28. <div 29. 30. 31. 32. 33. 34. <div data-role="content"> 38 <div data-role="header"> <h1>Page 2</h1> </div><!-- /header --> data-role="page" id="page-2"> </div> <div data-role="footer"> <h2>Demo ="text-decoration: By <a href="" target="_blank" style none; ">Kayo</a></h2> </div> <div data-role="content"> <header data-role="header"> <h1>jQuery Mobile </header> Demo</h1> data-role="page" id="home"> <title>jQuery Mobile <meta <meta <link Demo</title> initial-scale=1"> http-equiv="Content-Type" content="text/html; charset=UTF-8" /> name="viewport" content="width=device-width, rel="stylesheet" /> href="
bile-1.1.0.min.css"
<script src=""></script> <script src=" "></script>
35. 36. 37. 38. 39. 40. target="_blank" 41. 42. 43. 44. </div> 45. 46. <div 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. " 58. 59. 60. </div> 61. 62. </body> 63. </html> </div> <div data-role="footer"> <h2>Demo By <a href="" target="_blank </div> <div data-role="content"> <div data-role="header"> <h1>Page 3</h1> </div><!-- /header --> data-role="page" id="page-3"> <div data-role="footer"> <h2>Demo By <a style="text-decoration: </div> none; ">Kayo</a></h2> href="" </div>
style="text-decoration: none; ">Kayo</a></h2>
3. Ajax 驱动的站点
jQuery Mobile 默认会以 Ajax 的方式构建网站和应用,因此,同一域名下的所有 页面的跳转都会转为 Ajax 请求,并会配合 CSS3 动画作为页面跳转的过场。之所以采 用这样的机制,一方面是因为移动设备所能用的网络速度相对 PC 来说会较低, Ajax 可以减少跳转到新页面所需的带宽,另一方面, Ajax 配合 CSS3 动画能做出原生 App 的用户体验。如:当用户点击一个链接时, jQuery Mobile 会分析该 url ,产生 Ajax 请求,并显示一个正在加载的提示框,避免了刷新整个页面。若该次 Ajax 请求成功, 则会把新内容加载到 DOM 中,初始化所有组件,并显示页面过场动画。若请求失败, 则会显示一个错误提示框,并在几秒后消失。
39
另外,带有 rel="external" 属性的链接不会通过 Ajax 方式加载,跳转时整个页 面会被刷新。若需指定某个链接不需要 Ajax ,也可以为该链接添加 data-ajax="false" 属性, 这样的链接也不会使用 Ajax 。 关于 Ajax 的内容, Kayo 会 在介绍配置 jQuery Mobile 时详细介绍。
4. 页面转场
jQuery Mobile 为自带有一套基于 CSS3 的转场效果,你可以为任何能触发页面跳转的 链接添加 data-transition 属性来调整转场动画效果。这些效果基于 CSS3 的 transitions ,某些移动平台对 transitions 的支持并不足够,如果你的页面在转场 时出现闪烁的情况, Kayo 建议你在 CSS 中加入下面这一条 CSS 规则: .ui-page { -webkit-backface-visibility: hidden; } 另外, 若需要页面翻转等 3D 效果, 浏览器必须支持 3D transforms , 若不支持(如 安卓 2.x 系列),则会退化为淡出淡入的效果。 默认情况的转场效果是“fade”,即淡出淡入,若需要自定义转场效果,可以使用 data-transition 属性,如把转场效果改为“pop(弹出)”:
<a href="#page2" data-role="button" data-transition="pop">dialog</a>
该属性的具体取值可以查看本文末的完整 Demo,里面列举了 data-transition 所 有可取值。 小补充:控制转场宽度:当转场页面的宽度过大时,翻转等 3D 效果可能会过度消 耗系统资源, 因此开发者可以使用 $.mobile.maxTransitionWidth 控制转场最大宽度, 超过该宽度则不使用转场动画。$.mobile.maxTransitionWidth 是配置 jQuery Mobile 默认值的方法,因为比较复杂,将会另外写文章详解,这里列出该方法仅供有经验的开 发者参考。
5. 对话框 如下面的例子,为 Page 添加 data-rel="dialog" 属性,可以把页面表现 为对话框的形式——增加圆角,外边距,阴影和遮罩层。
40
<a href="#page-2"
data-role="button" data-rel="dialog" data-transition="fade" data-inline="true">dialog</a>
对话框也是一个 Page , 因此也有转场效果, 不过默认的效果是“slide”, 即滑动出现。需要注意的是,对话框通常作为辅助页面的用途(如登录框,提示 框),因此 jQuery Mobile 不会在历史记录的哈希值里记录对话框。
八、 jQuery Mobile 导航模型
看了上面的文字, 也许你会对其中的内容感到迷惑! 的确, jQuery Mobile 作 为一套完善的移动前端解决方案,它的处理机制会比较复杂。jQuery Mobile 的 导航模型,也就是 jQuery Mobile 的基本工作流程,了解完整的工作流程更有 助于童鞋们理解上面的内容。 当一个 jQuery Mobile 文档被打开时, Page 容器被请求, 插入到页面的 DOM 中,若页面中有多个 Page ,则会插入多个 Page ,但只有第一个 Page 在页面 上会被直接显示, 其他 Page 会隐藏起来, 直到用户点击相应的链接才会以 Ajax 的方式跳转到另一个 Page 。
41
这就是 jQuery Mobile 导航的简单描述,jQuery Mobile 也就是在页面间 跳转并处理 DOM 的,而这套机制都是基于 location.hash 属性的。当 jQuery Mobile 加载完第一个页面时, 它会以页面相对于 url 的完整路径产生 hash 值, Ajax 不改变当前 url ,而改变 hash 值则可以保证当前 url 能表示当前的页 面,如我们从 index.html 跳转到管理页面,则 url 也会更新为 index.html#admin(假设管理页面与主页在同一个 HTML 文档中并且 id 为 admin),这样这个 url 就能表示当前页面,若我们需要收藏这个页面,直接收 藏即可。 于是最后就有了上面所说的 Ajax 驱动机制——当用户点击一个非外部链 接时, hash 值发生变化, 同时 jQuery Mobile 阻止链接的默认行为, 并以 Ajax 的方式引入新内容,当新内容成功返回时更新 location.hash 的值,从而更新 url 。 现在整个导航模型以及 jQuery Mobile 的基本工作原理都已很清晰了,接 下来再补充一点。 在 jQuery Mobile 页面的 head 中, 加入了一个 base 标签, 该标签的值指向当前页面资源(图片,css,js)的正确获取路径,当页面变化 时,base 的值也会作出相应的变化。 这里科普一下 base 标签,下面引用 w3school 对 base 标签的解释: <base> 标签为页面上的所有链接规定默认地址或默认目标。通常情况下,浏 览器会从当前文档的 URL 中提取相应的元素来填写相对 URL 中的空白。使用 <base> 标签可以改变这一点。浏览器随后将不再使用当前文档的 URL,而使用 指定的基本 URL 来解析所有的相对 URL。 这其中包括 <a>、 <img>、 <link>、 <form> 标签中的 URL。 1. 预读取与缓存页面 开发者可以通过 data-prefetch 属性预读取一个页面,这样当你打开一个 文档时,可以为另外一个文档在本文档中的链接添加 data-prefetch 来预先读
42
取它, 这个文档通常是用户很有可能点击的页面,这样对于提升用户体验具有不 错的效果。 那为什么不直接把两页面放在同一个文档中呢? 因为如果把很多的 Page 放在一个文档中,这个文档的 DOM 会变得很大, 这样对于一些性能较差的移动设备来说会造成压力, 预读取的方式则可以减少这 种压力。 比如我们需要缓存 page2.html (注意跟上面的 #page2 区分开来,这里的 page2.html 是独立的一个 HTML 文档),只需要在跳转到 page2.html 的链接 上添加 data-prefetch 属性: <a href="Page2.html" data-prefetch>Page2</a>
但这仍然会有问题, jQuery Mobile 会通过 Ajax 的方式加载页面,这样一旦 点击的页面多了,DOM 将会变得很大,于是 jQuery Mobile 还做了一个机制来 应对这个情况——当一个页面通过 Ajax 加载到 DOM 中后,jQuery Mobile 会 标记这个页面, 当导航到其他页面时, 这个页面会从 DOM 中移除, 从而保持 DOM 的干净。 这个机制只适用于 Ajax 加载的其他文档的页面, 同一页面的多个 Page 通过 Ajax 显示/隐藏并不适用于这个机制。若需要缓存某个页面,以便用户从 其他页面重新回到该页面时可以快速浏览可以使用 data-dom-cache="true" 属 性: 如需要缓存上面例子中的 page2.html
<a href="Page2.html" data-prefetch data-dom-cache="true">Page2</a>
一旦缓存页面会使 DOM 变得很大,建议开发者在网站上线前进行足够的测试。 2. 其它 多 Page 页面中虽然把第一个容器加载作为第一个页面,但实际上所有 Page 是同时存在于同一个文档中,因此需要注意保持页面中容器的 ID 唯一。
43
jQuery Mobile 通过 Ajax 请求页面,但它只会将新页面的 body 内容插入到 DOM 中, 这意味着 head 部分引用的 js 对新内容无效,因此建议在每一个页面 都引用相同的 js , 即把所有的 js 都写到同一文件中并在 head 中引用,并且 这些 js 中用到的效果最好使用 live, delegate 等持续性方法匹配到元素中, 这样 js 中的效果对通过 Ajax 引入的新元素也有效。当然,jQuery Mobile 中 的 js 的所有方法都已经采用了相似的办法使到其对新元素也有效。当然,开发 者也可以使用 pagecreate() 的方法为某一个页面指定一个 js。
九、 jQuery Mobile 默认配置与事件基础
1. 一.默认配置 jQuery Mobile 会有一些默认的设置,如之前介绍过的 Ajax 导航形式,可 以选择在默认配置中关闭,这样整个网站都会关闭 jQuery Mobile Ajax 导航。 jQuery Mobile 把所有这些配置都封装在 $.mobile 中,作为它的属性,因此改 变这些属性值就可以改变 jQuery Mobile 的默认配置。 当 jQuery Mobile 开始执行时,它会在 document 对象上触发 mobileinit 事件, 并且这个事件远早于 document.ready 发生,因此开发者需要通过如下的 形式重写默认配置:
$(document).bind("mobileinit", // 新的配置 }); function(){
由于 mobileinit 事件会在 jQuery Mobile 执行后马上触发,因此开发者需要 在 jQuery Mobile 加载前引入这个新的默认配置,若这些新配置保存在一个名
44
为 custom-mobile.js 的文件中,你按如下顺序引入 jQuery Mobile 的各个文 件。
<script <script <script src="jquery.min.js"></script> src="custom-mobile.js"></script> src="jquery-mobile.min.js"></script>
下面以 Ajax 导航作为例子说明如何自定义 jQuery Mobile 的默认配置: 在之前的文章《使用 jQuery Mobile 与 HTML5 开发 Web App —— jQuery Mobile 页面与对话框》中说明过,jQuery Mobile 是以 Ajax 的方式驱动网站 (可以参加上文的第三点“Ajax 驱动的站点”),若某个链接不需要 Ajax , 可以为某个链接添加 data-ajax=”false” 属性,这是局部的设置,如果开发 者需要取消默认的 Ajax 方式(即全局取消 Ajax),可以自定义默认配置:
代码如下: $(document).bind("mobileinit", function(){ $.mobile.ajaxEnabled = false; }); jQuery Mobile 是基于 jQuery 的,因此你也可以使用 jQuery 的 $.extend 扩展 $.mobile 对象,
$(document).bind("mobileinit", $.extend($.mobile, {
function(){
ajaxEnabled: false }); });
使用上面的第二种方法可以很方便的自定义多个属性,如在上例的基础上同时设置 activeBtnClass , 即为当前页面分配一个 class, 原本的默认值为 “ui-btn-active”, 现在设置为“new-ui-btn-active”,可以这样写:
$(document).bind("mobileinit", function(){ $.extend($.mobile, { ajaxEnabled: false,
45
activeBtnClass: "new-ui-btn-active" }); });
上面的例子中介绍了简单同时也是最基本的 jQuery Mobile 事件,它反映了 jQuery Mobile 事件需要如何使用,同时也要注意触发事件的对象和顺序。 下面列出所有的默认配置及说明。(以属性名、值的类型、默认值的方式说明)
activeBtnClass 字符串 默认值:"ui-btn-active" 为激活状态的按钮分配 class 值。 activePageClass 字符串 默认值:"ui-page-active" 为当前页面分配 class 值。 ajaxEnabled 布尔型 默认值:true 控制是否禁止默认的 Ajax 链接点击和
表单提交,并停止 hash 的监听,然后以常规的 HTTP 方式进行。 allowCrossDomainPages 布尔型 默认值:false
设置是否允许跨域。因为 jQuery Mobile 会记录 location hash ,这有 可能会为网站带来 cross-site scripting (XSS) 攻击,因此该选项默认 为 false 。 autoInitializePage 布尔型 默认值:true
当 DOM 加载完毕后,jQuery Mobile 会自动调用 $.mobile.initializePage 方法。如果设置该属性为 false ,则页面不进行初始化,即页面空白。 buttonMarkup.hoverDelay 整形 默认值:200
该属性设置触摸触摸某一个 jQuery Mobile 按钮后添加 hover 和 down 的 class 的延时。该数值越小,延时越小,触摸越灵敏,但同时很有可能错误 的触发页面滚动条滚动。因此建议数值不要太小。 defaultDialogTransition 字符串 默认值:"pop"
设置使用 Ajax 方式的对话框的默认过场动画。 defaultPageTransition 字符串 默认值:fade
46
设置使用 Ajax 方式跳转的页面的默认过场动画。 gradeA 布尔型 默认值:"true"
设置 $.support.mediaquery 的返回值,默认为符合全部 grade A 等级的移 动设备的支持条件才会返回 true 。 hashListeningEnabled 布尔型 默认值:true
设置是否监听和处理 location.hash 的改变。 ignoreContentEnabled 布尔值 默认值:false
把该选项设置为 true , 并且在某元素的父元素上设置 data-enhance="false" 属性, 那么 该元素会自动降低 jQuery Mobile 增强(jQuery Mobile 元素增强指的是 jQuery Mobile 对网页基本元素在样式上的丰富、交互上的增强以及相应的 HTML 结构改造)。 linkBindingEnabled 布尔值 默认值:true
jQuery Mobile 会自动绑定锚标记到文档中,设置该选项为 false 将阻止所有的锚点击处 理, 例如取消激活按钮状态。 一般来说只有在把锚标记处理交给另一个处理库时才设置该属 性为 false 。 loadingMessageTextVisible 布尔值 默认值:false
设置当页面加载中的时候是否显示提示文字。 loadingMessage 字符串 默认值:"loading"
设置当页面显示加载提示时,加载提示文字的内容。 loadingMessageTheme 字符串 默认值:"A"
设置当页面显示加载提示时,加载提示的默认主题。 minScrollBack 整形 默认值:250
设置页面最小滚动距离 NS 字符串 默认:""
该属性可以改变 jQurey Mobile 的命名空间,jQuery Mobile 按 data-NS 属性值安排命名 空间,默认为空,则直接 data-role ,举个简单的例子,若设置 NS 的值为 "custom" , 则此时需要定义一个 jQuery Mobile 头部的话需要从原来的 data-role="header" 改为 data-custom-role="header" ,其他 data-role 也要改成为 data-custom-role 。这样开
47
发者可以创建属于自己的命名空间,避免与 jQuery Mobile 原有的属性发生冲突, 便于制 作自定义主题。 需要注意的是,当你使用了 data-命名空间后,你需要更新 jQuery Mobile css 文件的选 择器,格式如下 .ui-mobile [data-custom-role=page], .ui-mobile [data-custom-role=dialog] ...... pageLoadErrorMessage 字符串 默认值:"Error Loading Page"
设置当 Ajax 加载页面错误时显示的提示信息。 pageLoadErrorMessageTheme 字符串 默认值:"e"
设置当 Ajax 加载页面错误时错误提示框的主题样式。 pushStateEnabled 布尔型 默认值:true
在支持的浏览器中开启 history.replaceState 这个增强特性,把哈希值(hash-based)的 Ajax 请求转化为完整的文档路径。jQuery Mobile 建议在关闭 Ajax 导航和大量使用外部 链接的情况下关闭这个特性。 subPageUrlKey 字符串 默认值:"ui-page"
URL 参数用来指向由组件生成的子页面(如嵌套列表页),该 URL 会被解释成如 example.html&ui-page=subpageIdentifier 的形式,而在 &ui-page= 之前的哈希值会被 jQuery Mobile 向此 URL 地址做 Ajax 请求。 touchOverflowEnabled 布尔型 默认值:false
设置是否使用设备的原生区域滚动特性, 除了 iOS5 之外大部分的设备到目前还不支持原生 的区域滚动特性,因此在 jQuery Mobile 1.1.0 中不建议修改该属性。
2. 事件基础
通过上面的基本配置, 相信大家对 jQuery Mobile 的事件也有一定了解, 这里 Kayo 再正式介绍一下 jQuery Mobile 的事件。 jQuery Mobile 在基于本地事件上,创建了一系列的自定义事件,大部分事件是基 于触摸设备的使用情况开发的,当然这些事件对于桌面环境也会有适当的处理,开发者 可以使用 bind() 函数绑定到需要的页面对象中。
48
值得注意的是,jQuery Mobile 是基于 Ajax 导航的,所以采用 bind() 方法绑定的事 件无法作用于 Ajax 产生的网页元素中,因此建议开发者使用动态绑定的方法如 live()、delegate() 将事件动态的绑定到相应的元素中。live()、delegate() 等方法 可以把 jQuery Mobile 选择器选择的 DOM 元素,在整个 DOM 范围将其持久化,这就 意味着, 无论该元素是先前存在还是通过 Ajax 动态加载的, 事件都会被绑定, 如同 CSS 给元素添加样式一样。这在对 Ajax 有比较大依赖的网站中是必须注意的。 live()、delegate() 在实现动态绑定的原理和资源消耗方面也有很大的差别。 “刚刚在网友提醒下,了解到在 jQuery 1.7 中,引入了一个新的事件绑定函数 —— .on() ,用于代替 bind, live, delegate 。但 jQuery Mobile 文档仍建议使 用 .bind() 和 .live() 方法绑定事件,jQuery Mobile 并没有明确其中原因,但考虑 到低版本的 jQuery Mobile 只需 jQuery 1.6.4 的支持就足够,出于兼容性的原因, 当然也可能是由于考虑到开发者的习惯,jQuery Mobile 才作出以上建议。当然如果开 发者熟悉 .on() 方法也不妨采用 .on() 进行事件绑定。” 下面以其中的 live() 方法举一个例子说明如何动态绑定 jQuery Mobile 事件。
$(function(){ $("body").live('swiperight', function() { $('#next').click(); // #next 为下一页的链接的 id }); });
说明:上面的例子中,假设进入下一页的链接的 id 为 next 。那么在页面 上向右滑动就会触发点击了下一页的链接,从而进入下一页。可以想象,这个过 程是 Ajax 的,页面会平滑的跳转并且会有过场动画,这样从视觉上看,可以很 好的做出原生 App 中常见的滑动翻页功能。当然,这些是基于浏览器的,如果 用户的移动设备配置不高的话, 会很容易造成画面不流畅等降低用户体验的情况, 这也是 Kayo 在前文中建议不要使用过于炫丽的过场动画(如 3D transforms) 的原因之一。
49
通过上面的例子,不难看出 jQuery Mobile 的强大和方便,它考虑了很多 开发 Web App 需要用到的功能。
十、 jQuery Mobile 事件详解
注意不能使用前文中自定义默认配置时利用 jQuery 的 $.extend 扩展 $.event 对象的方法扩展 $.event 对象,只有 $.mobile 可以使用 $.extend 扩展对象。 因此事件 API 中只有 $.mobile.orientationChangeEnabled 可以使 用 $.extend 方法进行自定义。 1. 触摸事件使用例子
下面的例子会使用 live() 为两个页面的 body 元素分别绑定 swiperight 和 swipeleft 事件, 这样在页面上向右划动和向左划动可以在两个页面之间切换。 并且本例子 会结合“修改配置例子”的调整, 把触发 swipe 事件的最小水平拖曳距离和触发 swipe 事 件的最大垂直拖曳距离分别修改为 100 和 120 , 读者可以尝试水平划动默认的 30(px) 或 垂直方向上滑动超过默认的 75(px) 以检测修改是否有效。
为了达到最好的效果,建议在支持触摸的设备上测试,若使用桌面环境测试,建议在页 面空白地方点击鼠标划动。 另外由于划动距离已自定义为较大的值, 划动时若没有效果不妨 加大划动距离。 jQurey Mobile 代码 $(document).bind('mobileinit', function(){ $.event.special.swipe.horizontalDistanceThreshold = 100; // 修改触发 swipe 事件的最小 水平拖曳距离为 100(px) $.event.special.swipe.verticalDistanceThreshold = 120; // 修改触发 swipe 事件的最大垂 直拖曳距离为 120 (px) }); $(function(){ $("#home").live('swipeleft', function() {
50
$('#toPage2').click(); // 为首页绑定向左划动事件 }); $("#page-2").live('swiperight', function() { $('#toHome').click(); // 为另一页面绑定向右划动事件 }); }); 主要 HTML 代码 <div data-role="page" id="home"> <div data-role="header"> <h1>jQuery Mobile Demo</h1> </div> <div data-role="content"> <p> 本例子中,为两个页面的 body 元素分别绑定了 swipeleft 和 swiperight ,划动后 分别触发相应的链接,转到另一个页面,另外使用 data-transition="slide" 把页面过场改 为“滑动”效果,从而达到 Apps 中常用的滑动换页效果。</p> <a id="toPage2" href="#page-2" data-role="button" data-transition="slide" data-theme= "b">向左滑动触发我这个链接</a> </div> <div data-role="footer"> <h2>Demo By <a href="" target="_blank" style="text-decoration: no ne; ">Kayo</a></h2> </div> </div> <div data-role="page" id="page-2"> <div data-role="header"> <h1>jQuery Mobile Demo</h1> </div> <div data-role="content"> <a id="toHome" href="#home" data-role="button" data-theme="b" data-transition="slide" data-direction="reverse" data-rel="back"> 向右滑动触发我这个链接</a> </div> <div data-role="footer"> <h2>Demo By <a href="" target="_blank" style="text-decoration: no ne; ">Kayo</a></h2> </div>
51
</div>
2. jQuery Mobile 页面事件与 deferred 下面再对 $.mobile.loadPage() 的源码进行分析,这里会为整个 $.mobile.loadPage() 方法的源码进行注释,但为了方便阅读,不会列出全部的 源码实体,以源码注释代替完整源码。
$.mobile.loadPage = function( url, options ) { // 创建一个 deferred 对象, 用于告知调用者 $.mobile.changePage() 页面请求成功或是出现错 误,也就是让 $.mobile.changePage() 知道需要调用 done() 或是 fail() 回调队列 var deferred = $.Deferred(), // … 根据参数处理页面数据 … // 触发一个 pagebeforeload 事件 var mpc = settings.pageContainer, pblEvent = new $.Event( "pagebeforeload" ), // 保存页面选项在 data 参数中 triggerData = { url: url, absUrl: absUrl, dataUrl: dataUrl, deferred: deferred, options: settings }; // 让监听器知道正准备加载一个新页面 mpc.trigger( pblEvent, triggerData ); // 如果开发者阻止了默认行为,本函数马上结束,并返回 deferred 对象的 promise() 方法 if ( pblEvent.isDefaultPrevented() ) { return deferred.promise(); } // 提示正在加载页面 // 使用 ajax 把页面插入 DOM ,然后根据 ajax 请求成功还是失败作出相应的处理 // 请求成功 /* 根据实际情况和传递的参数调整页面内容(调整 jqm header, jqm title, 移除 loading 提示 等) 触发 pageload 事件告知监听者页面请求成功 */ // 调用 resolve() 方法使 deferred 状态为成功 deferred.resolve( absUrl, options, page, dupCachedPage ); // 请求失败 /* 报错并对页面作出一个调整(移除 loading 提示等) 触发 pageloadfail 事件告知监听者页面请求失败 */ // 调用 rejected() 方法使 deferred 状态为失败 deferred.reject( absUrl, options ); // 返回一个 deferred 对象的 promise() 方法 return deferred.promise(); };
52
看了上面的代码和注释后, 相信大家对页面加载的流程以及页面事件的触发时间已经有 了完整的理解,deferred 对象起到了控制使用哪种回调的作用,这些回调的具体内容 是在 $.mobile.changePage() 中分别以 done() 和 fail() 指定的。 若用户没有阻止事件的默认行为,则根据请求成功或失败,会调用 resolve() 或 rejected() 方法改变 deferred 的状态,然后根据状态判断是调用 done() ,或是直 接调用 fail() 。 若用户阻止事件的默认行为,jQuery Mobile 会马上终止加载页面,并返回一个 deferred 的 promise() 方法,promise() 方法返回的是 deferred 的只读版本,即返 回一个可读不可写的 deferred 对象,除此之外没有任何处理了。但是上面的源码注释 中已经说明,$.mobile.loadPage 会把一系列的属性保存在 data 参数中,其中包括了 deferred 对象,我们知道,开发者可以为事件绑定一个回调函数,这个 data 对象会 被分配到 pagebeforepage 事件的回调函数的第二个参数中 (第一个参数为事件本身) , 因此我们可以调用这个 data.deferred 对象的 resolve() 或 rejected() 方法恢复 请求,实际上这里的恢复请求是告知调用者 $.mobile.changePage() 这次 ajax 请求 是成功还是失败,使到 $.mobile.changePage() 方法知道需要调用 done() 回调队列 还是直接调用 fail() 回调队列。 resolve() 或 rejected() 中填写的参数实际上也就是 done() 或 fail() 中相 应的参数。 当然,若开发者没有阻止默认行为,这个 $.mobile.loadPage() 在最后也会触发 resolve() 或 rejected() 方法, 因此实际上有没有利用阻止默认行为进行自定义处理 的区别是 —— 是否进行页面处理和触发 loadpage 或 loadpagefailed 事件, 即自定 义处理不会有上面的源码注释中使用 /* */ 注释的部分, 或者说, 自定义处理需要做的, 就是自行设计一些处理,来代替 /* */ 注释中的默认处理。 这就意味着, 若有需要的话, 阻止默认行为并进行自定义处理页面 (调整 jqm header, jqm title 移除 loading) 后还必须手动触发 loadpage 事件或 loadpagefailed 事件。
53
在说明整个加载页面流程后, 这里再介绍一下上面所说的传递给 pagebeforeload 事件 的回调函数的第二个参数 —— data 的各项属性。
? ? ? ? ?
url (string) 通过回调函数传递绝对或者相对的 url 到 $.mobile.loadPage() absUrl (string) 绝对 url dataUrl (string) 当识别页面或者更新浏览器地址的时候使用过滤过的绝对 url deferred (object) 回调函数中调用 preventDefault() ,必须使用 resolve() 或 rejected() 恢复 changePage() 请求 options (object) 这个对象包含了需要传递给 $.mobile.loadPage() 的选项
最后引用 jQuery Mobile 官方的例子来说明如何阻止默认行为并进行自定义处理,为 了进一步说明,Kayo 会修改一下这些例子。
$( document ).bind( "pagebeforeload", function( event, data ){ // 阻止默认行为,告知浏览器本次事件由事件的回调函数(即本函数)处理 event.preventDefault(); // 自定义处理,如简单的弹出一个提示 alert('本次事件由开发者作出一些处理'); // 在本函数或者其它异步方法中调用 resolve() // 告知 $.mobile.changePage() 方法继续页面请求并执行 done() 回调函数队列 data.deferred.resolve( data.absUrl, data.options, page ); }); 调用 reject() $( document ).bind( "pagebeforeload", function( event, data ){ // 阻止默认行为,告知浏览器本次事件由事件的回调函数(即本函数)处理 event.preventDefault(); // 自定义处理,如简单的弹出一个提示 alert('本次事件由开发者作出一些处理'); // 在本函数或者其它异步方法中调用 rejected() // 告知 $.mobile.changePage() 方法继续页面请求并直接执行 fail() 回调函数队列 data.deferred.rejected( data.absUrl, data.options ); });
pageload
pageload 事件的触发流程相对 pagebeforeload 来说则较为简单, 当页面成功加载 并插入到 DOM 后会触发 pageload 事件,这个事件也会传递一个 data 参数作为事件
54
回调函数的第二个参数,但这个 data 参数与 pagebeforeload 的属性有些不同,下面 列出完整的属性。
? ? ? ? ?
url (string) 通过回调函数传递绝对或者相对的 url 到 $.mobile.loadPage() absUrl (string) 绝对 url dataUrl (string) 当识别页面或者更新浏览器地址的时候使用过滤过的绝对 url options (object) 这个对象包含了需要传递给 $.mobile.loadPage() 的选项 xhr (object) 当尝试加载页面时,会使用 jQuery XMLHttpRequest 对象,这个也 是 $.ajax() 成功回调函数的第三个参数
?
textStatus (null or string) 根据 jQuery 核心文档,请求时会以一个字符串描述状 态,这也是 $.ajax() 失败回调函数的第二个参数
可以看出,jQuery Mobile 没有为 pageload 提供 deferred 对象属性,这说明页面请 求成功后,只能按默认情况执行 done() 队列,不能利用 deferred 对象直接执行 fail() 队列。
pageloadfailed
pageloadfailed 事件是页面请求失败时触发的,参数与 pageload 相似,但这里 再次引入 deferred 对象,这表明 jQuery Mobile 允许开发者即使页面请求失败,仍 可利用 deferred 对象选择执行 done() 队列或 fail() 队列 。具体的 data 属性如 下。
? ? ? ?
url (string) 通过回调函数传递绝对或者相对的 url 到 $.mobile.loadPage() absUrl (string) 绝对 url dataUrl (string) 当识别页面或者更新浏览器地址的时候使用过滤过的绝对 url deferred (object) 回调函数中调用 preventDefault() ,必须使用 resolve() 或 reject() 恢复 changePage() 请求
? ?
options (object) 这个对象包含了需要传递给 $.mobile.loadPage() 的选项 xhr (object) 当尝试加载页面时,会使用 jQuery XMLHttpRequest 对象,这个也 是 $.ajax() 成功回调函数的第三个参数
55
?
textStatus (null or string) 根据 jQuery 核心文档,请求时会以一个字符串描述状 态,这也是 $.ajax() 失败回调函数的第二个参数
?
errorThrown (null, string, object) 根据 jQuery 核心文档,这个属性可能会被用作 HTTP 状态的一部分,这也是 $.ajax() 失败回调函数的第三个参数。
上面介绍 pagebeforeload 事件时, 已经介绍了使用 preventDefault() 阻止事件默认 行为,然后进行自定义的处理,并且重新使用 deferred 对象的 resolve() 或 rejected() 方法恢复页面请求。而在 pageloadfailed 事件中也有类似的做法,这里 的自定义处理通常是在页面请求失败后加载另一个页面,下面举例说明。
调用 resolve() $( document ).bind( "pageloadfailed", function( event, data ){ // 阻止默认行为,告知浏览器本次事件由事件的回调函数(即本函数)处理 event.preventDefault(); // 自定义处理,尝试加载另一个页面 // 在本函数或者其它异步方法中调用 resolve() // 告知 $.mobile.changePage() 方法继续页面请求并执行 done() 回调函数队列 data.deferred.resolve( data.absUrl, data.options, page ); }); 调用 rejected() $( document ).bind( "pageloadfailed", function( event, data ){ // 阻止默认行为,告知浏览器本次事件由事件的回调函数(即本函数)处理 event.preventDefault(); // 自定义处理,尝试加载另一个页面 // 在即本函数或者其它异步方法中调用 rejected() // 告知 $.mobile.changePage() 方法继续页面请求并直接执行 fail() 回调函数队列 data.deferred.reject( data.absUrl, data.options ); });
下面给出一个完整例子来验证自定义处理的方法中需要代替的是页面处理和触发 pageload 或 pageloadfailed 事件,本例子中,Kayo 阻止了 pagebeforeload 的默认 行为, 注意, Kayo 在例子中绑定了 pageload 事件, 并在其回调函数中添加弹出提示, 但因为进行自定义处理,不会产生 pageload 事件,因此不会弹出加载 pageload 事件 的提示,只有“自定义处理”的弹出提示。另外,读者可以尝试在 Demo 中的两个页面
56
中来回点击几次,会发现只有第一次点击会弹出“自定义处理”提示,这是因为第一次 加载另一个页面后, 该页面已经存在于 DOM 中, 再次加载不会触发 pagebeforeload 事 件。读者可以在 Demo 中验证以上两点。 页面加载事件 Demo(建议使用 PC 上的 Firefox、Chrome 等现代浏览器和 IE9+ 或 Android , iPhone/iPad 的系统浏览器浏览,下同)
3. 页面跳转事件 (Page change events)
页面跳转事件与页面加载事件类似,但因为没有直接使用 deferred 对象,因此这 系列的事件会较为简单。 页面跳转事件由 $.mobile.changePage() 产生,第一个为 pagebeforechange , 第二个是 pagechange 或 pagechangefailed 。 $.mobile.changePage() 方法调用后会对页面参数进行一些处理,然后触发 pagebeforechange 事件,若页面请求成功,即上面的 $.mobile.loadPage() 调用了 done() 队列,并且页面外部处理(history 等)完成后,会触发 pagechange ,若请 求失败,即上面的 $.mobile.loadPage() 直接调用了 fail() 队列,则触发 pagechangefailed 事件。 实质处理页面加载的是 $.mobile.loadPage() 事件,因此需要进行页面加载前后 的自定义处理还是用阻止 pagebeforeload , pageload, pageloadfail 等事件并进行 自定义处理比较合适,尽管这样,阻止 pagebeforechange 仍具有意义 —— 它可以直 接阻止一个页面加载,在某些情况下,可能你会需要这样做,就像有些情况下需要阻止 click 的默认跳转行为一样。 这三个事件的回调函数的第二个参数 data 有如下两个属性:
?
toPage (object or string) 这个属性值应该为一个希望被激活的页面(即需要进入 的页面) ,实际取值可以为一个包含页面 DOM 对象的 jQuery 对象或者一个外 部页面的绝对或相对链接,这个值同时也是 $.mobile.changePage() 方法的第一 个参数。
57
?
options (object) 这个值是一个包含页面选项的对象,同时也会用于 $.mobile.changePage() ,作为第二个参数。
利用上面两个属性,可以在事件回调函数中作出一些处理。 值得注意的是,通过了解加载页面的流程,可以知道,一次正确的页面跳转中,事 件产生的顺序应该是, pagebeforechange , pagebeforeload , pageload , pagechange , 在开发时需要注意这些事件的触发顺序。
4. 页面显示/隐藏事件 (Page show/hide events)
在页面转场前后, 会触发一些事件, 举一个例子: B 页面中有一个 id 为 page-B 的 page 组件 ,然后在 A 页面的 head 中作出如下的事件绑定:
$('#page-B').live( 'pagebeforeshow', function(event, ui){ alert('pagebeforeshow'); }); $('#page-B').live( 'pagebeforehide', function(event, ui){ alert('pagebeforehide'); }); $('#page-B').live( 'pageshow', function(event, ui){ alert('pageshow'); }); $('#page-B').live( 'pagehide', function(event, ui){ alert('pagehide'); });
从 A 页面点击链接跳转到 B 页面,然后从 B 页面跳转回 A 页面,则触发事件的情况 如下,
? ? ? ?
pagebeforeshow:从 A 跳转到 B,B 页面被显示时(转场开始)触发 pagebeforehide:从 A 跳转到 B,A 页面被隐藏时(转场结束)触发 pageshow:从 B 跳转到 A,A 页面被显示时(转场开始)触发 pagehide:从 B 跳转到 A,B 页面被隐藏时(转场结束)触发
因此,触发哪种页面显示/隐藏事件,要视乎页面是被显示还是被隐藏。
58
这些事件会由转场实现函数控制触发, 它们的回调函数的第二个参数 data 只有一个属 性,分别为:
?
pagebeforeshow:prevPage (object) 这个属性值应为包含正在离开的页面 DOM 对象的 jQuery 对象,即上面的 $(A)
?
pagebeforehide: nextPage (object) 这个属性值应为包含正在进入的页面 DOM 对象的 jQuery 对象,即上面的 $(B)
?
pageshow: prevPage (object) 这个属性值应为包含正在离开的页面 DOM 对象的 jQuery 对象,即上面的 $(B)
?
pagehide: nextPage (object) 这个属性值应为包含正在进入的页面 DOM 对象的 jQuery 对象,即上面的 $(A)
下面给出一个 Demo ,演示上面 A 与 B 页面的例子
5. 页面初始化事件 (Page initialization events)
页面初始化中的初始化指的是页面增强,即 jQuery Mobile 对页面组件的样式、 功能和交互进行丰富并增强的过程,在这个过程中也会触发一系列事件。
pagebeforecreate
在页面开始初始化之前触发,这时 DOM 已被 jQuery Mobile 获得,但仍未 进行 jQuery Mobile 增强,因此绑定这个事件并在回调函数中作出处理可以在 页面被增强前进行自定义处理。 另外若阻止事件的默认行为,会禁止页面组件初始化。是否觉得这个流程与 pagebeforeload 的流程相似,的确,在 jQuery Mobile 中,很多事件的产生函 数(如 pagebeforeload 的产生函数 pagebeforeload)内部都有阻止默认行为 的处理, 即用判断语句判断触发阻止默认行为后自动 return ,阻止后面的处理 发生,了解这个流程对于了解 jQuery Mobile 的工作原理很有帮助。
59
pagecreate
在页面初始化时,即 DOM 刚开始被创建,并且需要进行 jQuery Mobile 的元素 已经准备好(即加入待增强列表),但仍未实际开始进行 jQuery Mobile 增强 前触发。
pageinit
当页面初始化后触发,jQuery Mobile 建议使用这个事件的绑定代替 jQuery 中 常用的 DOM ready() ,因为触发这个事件意味着页面已经直接或者通过 Ajax 加载好并增强,更适合用在 jQuery Mobile 开发中。 6. 页面移除事件 (Page remove events)
页面移除事件只有一个 —— pageremove ,当 jQuery Mobile 准备从 DOM 中移除一 个外部页面时会触发这个事件,阻止这个事件的默认行为可以阻止一个页面被移除。
十一、
jQuery Mobile 方法
对比于 jQuery 方法可以实现 DOM 遍历,动画,Ajax 等各种丰富的操作, jQuery Mobile 的方法更像是 jQuery Mobile 的配置方案,它的主要功能是调 整 jQuery Mobile 的效果或运行方式,尤其是页面加载和解析 URL 的部分,而 jQuery Mobile 方法基本都会在 jQuery Mobile 的默认执行中被内部调用,当 然作为一系列完整的方法,开发者也可以手动执行它们,以创建更灵活的 Web Apps 。下面 Kayo 详细介绍 jQuery Mobile 的方法,由于方法较多,会分为两 篇文章介绍,本文介绍的是与页面加载相关的方法。 1. $.mobile.changePage() & $.mobile.loadPage()
$.mobile.changePage() 与 $.mobile.loadPage() 方法是 jQuery Mobile 用于加载页 面的方法, 由于与页面事件有紧密的关联, 因此在上一篇系列文章 《使用 jQuery Mobile
60
与 HTML5 开发 Web App —— jQuery Mobile 页面事件与 deferred》中已经作了详细 介绍,包括这两个方法的具体流程和及其技术原理,这些内容可以浏览前文的第一、二 部分。而本文中会补充这两个方法的参数及对两个方法稍作总结。
$.mobile.changePage()
$.mobile.changePage() 方法会在页面加载时自动调用, 若这个页面为当前 文档中的不同 "page",则会转到这个新页面隐藏旧页面;若这个页面为外部页 面,即页面与当前页面不在同一文档中(本质上是新页面不在当前 DOM 中), $.mobile.changePage() 首先会调用 $.mobile.loadPage() 把外部页面的元素 插入到 DOM 中,再显示新页面。这也是对页面加载过程的简单复述。 $.mobile.changePage() 有两个参数 to (string or object, 必须) 和 options (object, 可选),具体如下:
—— to (string or object, 必须)
to 为必要参数, 其值可以为 string(字符串, 如 "about/us.html") 或 object(对 象, 如 $("#about")), 这主要是面向两种不同的页面, string 形式的为外部页面链接, 而 object 为同一文档中的不同 "page" ,如 "#page2" ,$.mobile.changePage() 会 把其处理成包含这个 DOM 的 jQuery 对象,即 $('#page2') 这种形式,而 $.mobile.changePage() 内部会判断 to 参数的形式,若是 string 则调用 $.mobile.loadPage() 把外部页面的元素插入到 DOM 中,再显示页面。
—— options (object, 可选)
options 为可选参数,其值为 object (对象),这个 object 包含多个属性,这 些属性储存一个页面的各种参数, jQuery Mobile 会根据这些参数来控制如何加载页面, 以及对页面进行初始化。具体属性值如下:
?
allowSamePageTransition (boolean, 默认值: false)默认情况下, $.mobile.changePage() 是不会理会跳转到当前页面的请求。把这个属性设置为 "true" ,则可以允许这种请求
61
? ?
changeHash (boolean, 默认值: true)判断地址栏上的哈希值是否应该被更新。 data (object 或 string, 默认值: undefined) Ajax 请求时发送的数据。仅当 to 参 数的值为一个 URL 时可用。
?
dataUrl (string, 默认值: undefined)当浏览器完成页面转换时要更新浏览器的地 址栏上的 URL 。如不特别指定,则使用 data-url 的属性值。
?
pageContainer (jQuery collection, 默认值: $.mobile.pageContainer)指定包含页面 的 DOM 对象的 jQuery 对象。
?
reloadPage (boolean, 默认值: false)强制刷新页面,即使页面容器的 DOM 已经 准备好仍然会执行刷新。仅当 to 参数的值为一个 URL 时可用。
?
reverse (boolean, 默认值: false)设置页面转场动画的方向。当该属性设置为 "true" 时页面转场反向。
?
role (string, 默认值: undefined)显示页面的时候使用 data-role 值。默认情况下 为 undefined,即取决于元素的 @data-role 属性值(标签上 data-role 的值) 。
?
showLoadMsg (boolean, 默认值: true)设置当加载外部页面时是否显示加载提示 信息。
?
transition (string, 默认值: $.mobile.defaultPageTransition)设置页面加载时使用的 过场动画。
?
type (string, default: "get")设置请求页面时使用的方法 ("get" 或 "post") 。仅当 to 参数的值为一个 URL 时可用。
这里引用例子说明一下 $.mobile.changePage() 的使用方法,手动调用该方法可 以触发跳转到一个新页面,例如,在 Web Apps 发生错误时可以跳转到一个提示错误的 页面。
// 转入到 "about us" 页面并使用 "slideup" 转场动画 $.mobile.changePage( "about/us.html", { transition: "slideup"} ); // 转入到 "search results" 页面, 使用 来自 id 为 search 的表单数据,并把页面请求方式改 为 "post" $.mobile.changePage('searchresults.php', { type: "post", data: $("form#search").serialize() });
62
// 转入到 "confirm" 页面并使用 "pop" 转场动画,不更新历史记录(地址栏哈希值不更 新) $.mobile.changePage('../alerts/confirm.html', { transition: "pop", reverse: false, changeHash: false }); 发生错误时可以跳转到一个提示错误的页面。 $(function(){ // 发生错误,以 "slideup" 的方式弹出对话框提示发生了错误 $.mobile.changePage('../alerts/confirm.html', { transition: "slideup", role: "dialog" }); });
$.mobile.loadPage()
如上面所述,$.mobile.loadPage() 用于加载一个外部页面,但这里的加载是指把 外部页面的元素插入到当前 DOM 中,并在插入之前对页面内容进行 jQuery Mobile 增 强 。该方法会被 $.mobile.changePage() 调用,条件是 $.mobile.loadPage() 的第 一个参数 to 为 string (即加载的页面为外部页面)。这个方法仅仅是进行插入 DOM 操作,不会影响当前激活的页面,所以它可以用于在后台加载页面(只插入 DOM 而不 显示页面),该方法会返回一个 deferred 对象,包含页面请求成功与否等相关信息, 并会在页面增强和插入 DOM 后分解这个对象。 $.mobile.loadPage() 有两个参数 url (string or object, 必须) 和 options (object, 可选),具体情况如下:
—— url (string or object, 必须)
该参数的值可以为 string 或 object , 无论是何种形式, 必须为一个绝对或相对 URL 。 若是由 $.mobile.changePage() 调用本方法时, 则该参数值为 $.mobile.changePage() 的 to 参数值。
—— options (object, 可选)
63
options 为可选参数, 其值为 object (对象) , 实际上如由 $.mobile.changePage() 调用本方法时,该参数值为 $.mobile.changePage() 的 options 参数值。因此这个 object 与 $.mobile.changePage() 的 options 选项值相同,其具体属性值请参考 $.mobile.changePage() 中 options 的属性值。 这里引用例子说明一下 $.mobile.loadPage() 的使用方法,手动调用该方法可以 在后台加载外部页面的元素并且不影响当前激活页面。
// 把 "about us" 页面加载到 DOM $.mobile.loadPage('about/us.html'); // 转入到 "search results" 页面, 使用来自 id 为 search 的表单数据,并把页面请求方式改 为 "post" $.mobile.loadPage('searchresults.php', { type: "post", data: $('form#search').serialize() });
2. $.fn.jqmData() & $.fn.jqmRemoveData()
当页面中使用了 jQuery Mobile ,jQuery Mobile 会使用 jqmData 和 jqmRemoveData 代替 jQuery 核心的 data 和 removeData 方法(注意,这包括了 jQuery 中的 $.fn.data , $.fn.removeData , $.data , $.removeData 和 $.hasData) , 这两个方法会自动获取和设置 data 属性的命名空间(即使当前没有使用命名空间)。 这两个方法的参数对应着 jQuery 的 data 和 removeData 方法的参数,具体如下:
—— jqmData( jQuery.data() )
? ? ?
element 与该 data 属性相关联的 DOM 对象 key data 的命名字符串 value data 属性的值
—— jqmRemoveData ( jQuery.removeData() )
? ?
element 与需要移除 data 属性相关联的 DOM 对象 name 需要移除的 data 的命名字符串
64
注意: 当通过 jQuery Mobile data 属性寻找元素时, 请使用自定义选择器: jqmData() ,它会在查询元素时自动合并 data 属性的命名空间。例如,你应该 使用 $('div:jqmData(role="page")') 代替 $('div[data-role="page"]') , 因为前者会自动映射到 $("div[data-"+ $.mobile.ns +'role="page"]') ,而 不需要强制把选择器与命名空间连接起来。例如:命名空间为 rn ,若使用后者 即为 $('div[data-rn-role="page"]') ,这时如果更改了命名空间,则这个选 择器便会失效, 而使用前者则会自动映射到当前选择器中,即使更改命名空间也 不会造成这个选择器失效。 但是也有例外的情况, 就是根据 URL 值在命名空间中选择 data 属性,例 如, jQuery Mobile 可以使用 :jqmData(url) 跟踪一个页面来自哪里, 根据 URL 中的命名空间来选择空间内的 data 属性。 这要求需要在选择器的括号内填写一 个有效的 URL 。 3. $.fn.jqmEnhanceable() 这是判断元素是否要进行 jQuery Mobile 增强的方法,默认情况下,所有 jQuery Mobile 组件都会通过此方法放入 jQuery Mobile 增强集,以交给另一 函数进行 jQuery Mobile 增强,包括添加相应的 HTML , CSS class 和交互。 这是 jQuery Mobile 默认调用的方法,并且没有任何可选参数,但该方法仍有 一个很值得注意的地方,在方法的实现函数内部,会判断默认配置 $.mobile.ignoreContentEnabled 的值,若为 true ,则会对调用该方法的 jQuery 对象的 DOM 父节点遍历,若父节点标签上设置了 data-enhance = "false" ,则不让该 DOM 对象加入增强集。事实上 jQuery Mobile 的官方文档 并没有阐述 $.fn.jqmEnhanceable() 的具体使用方法,反而用了不少篇幅介绍 这个注意事项。 另外还需要注意的是, 遍历操作会设计元素的所有父节点,因此即使遍历一 个很小的 jQuery 对象集的父节点也会消耗很多资源,开发则需要谨慎使用。若 开发时已经明确不需要对某元素进行增强,建议还是直接不使用 data-role 触 发相应的组件。
65
而如何设置 $.mobile.ignoreContentEnabled 的值,可以参考《使用 jQuery Mobile 与 HTML5 开发 Web App —— jQuery Mobile 默认配置与事件基础》 4. $.fn.jqmHijackable() 这是判断元素是否加入 jQuery Mobile Ajax 导航,即使用 Ajax 进行处 理的方法,与 $.fn.jqmEnhanceable() 相似,默认情况下这也是会为所有链接 和表单提交执行,使到它们可以加入 jQuery Mobile Ajax 处理集合,交给另一 函数处理。在 jQuery Mobile 内部,本方法与 $.fn.jqmEnhanceable() 最终都 是调用了 haveParents 方法,来判断元素是否应该加入相应的集合。因此,本 方法执行时会判断默认配置 $.mobile.ignoreContentEnabled ,若为 true , 则会对调用该方法的 jQuery 对象的 DOM 父节点遍历,若父节点上标签上设置 了 data-ajax = "false" ,则不让该 DOM 对象加入 Ajax 导航集。当然,在使 用这个特性时也需要注意遍历带来的大量资源消耗。 5. $.mobile.loading()
该方法从 jQuery Mobile 1.2 开始正式引进,控制显示或隐藏页面加载信息,包含两 个参数,第一个是控制页面信息加载与否,只有 "show" 和 "hide" 两个值,第二个参 数为多属性对象,具体的属性如下:
? ? ?
theme (string, 默认值: "a")加载信息条的主题样式 text (string, 默认值: "loading")加载信息条的文字内容 textonly (boolean, 默认值: false)若设置为 true ,则加载页面时 "spinner" 图片 (即旋形加载提示图,1.0 及之前版本为条形加载图)会被隐藏。
?
textVisible (boolean, 默认值: false)若设置为 true ,提示的文字内容会置于 spinner 之下
?
html (string, 默认值: "")如果个属性值不为空,则这个值会替代整个加载信息条 的 HTML
下面引用例子说明 $.mobile.loading 的使用方法。
// 提示页面正在加载 $.mobile.loading('show');
66
// 加载信息条使用主题样式 "b" , 自定义提示文字内容,隐藏 "spinner" 图片 $.mobile.loading('show', { theme: 'b', text: '给力的加载中', textonly: true }); 以下两个方法在 jQuery Mobile 1.2 中不赞成使用
6.
$.mobile.hidePageLoadingMsg()
显示页面加载信息,基于 $.mobile.loadingMessage 配置出来,具体有三个参数
o o o
theme (string, default: "a") The theme swatch for the message. msgText (string, default: "loading") The text of the message. textonly (boolean, default: false) If true, the "spinner" image will be hidden when the message is shown.
例子: // 使用主题样式 "b" ,自定义提示文字内容,隐藏 "spinner" 图片 $.mobile.showPageLoadingMsg('b', 'This is only a test', true); 在 jQuery Mobile 1.2 中,建议使用 $.mobile.loading('show') 代替。
7. $.mobile.hidePageLoadingMsg()
隐藏页面加载信息,基于 $.mobile.loadingMessage 配置出来,没有参数。 例子: // 隐藏页面加载提示信息 $.mobile.hidePageLoadingMsg();
在 jQuery Mobile 1.2 中,建议使用 $.mobile.loading('hide') 代 替。观察以上的方法,可以看出以上方法跟页面加载的过程都有关联。不过,以 上只是 jQuery Mobile 里的一部分方法,另外一部分方法主要跟页面 URL 解析 有关,还有一些其他的实用方法。
以下两个方法在 jQuery Mobile 1.1 中不赞成使用
8. $.mobile.fixedToolbars.show()
67
固定工具栏 (包括固定的头部栏和尾部栏)可以通过点击屏幕在显示与隐藏之间 切换,而这个方法则是手动显示一次工具栏。 它具有一个参数 immediately(boolean, 可选) 。把它设置为 true ,当前激 活页面的所有固定工具栏都会立即显示出来。若设置为 false 或者没有指定, 则会通过 100ms 的渐变显示出来。注意如 document 的 resize 和 scroll 等 事件会导致额外的延时显示。例子:
// 显示固定工具栏并且显示默认的渐变动画 $.mobile.fixedToolbars.show(); // 立即显示固定工具栏 $.mobile.fixedToolbars.show(true);
在 jQuery Mobile 1.1 中,不建议使用该方法,jQuery Mobile 并没有明确原 因,但根据 jQuery Mobile 的习惯,这很可能是因为这个方法有很多不稳定性, 如上面提到的遇到某些方法会出现额外的延时显示,这对于建立 Web Apps 是 很不好的影响因素,它会从底层部分为 Web Apps 带来不可预知的问题。 9. $.mobile.fixedToolbars.hide() 固定工具栏(包括固定的头部栏和尾部栏)可以通过点击屏幕在显示与隐藏 之间切换,而这个方法则是手动隐藏一次工具栏。 与 $.mobile.fixedToolbars.show() 相似,它具有一个参数 immediately(boolean, 可选) 。把它设置为 true ,当前激活页面的所有固定 的工具栏都会立即隐藏。 若设置为 false 或者没有指定,则会通过 100ms 的渐 变隐藏起来。 注意如 document 的 resize 和 scroll 等事件也会增加隐藏动画 的时间。
例子: 1. 2. 3. 4. 5. // 隐藏固定工具栏并显示默认的渐变动画 $.mobile.fixedToolbars.hide(); // 立即隐藏固定工具栏 $.mobile.fixedToolbars.hide(true);
68
在 jQuery Mobile 1.1 中,也不建议使用该方法。
10. $.mobile.path.parseUrl() 本方法用于解析一个 URL 和它的相对形式,并且它的相关成分放入一个对 象中,方便访问这些 URL 相关成分。当解析相对形式的 URL 时,返回的对象会 自动为绝对形式 URL 中没有的成分(如 protocol, host , etc )添加空字符 串作为值。另外,当解析的 URL 没有 authority (见下面的列表),返回的对 象中的 pathname 属性会包含通信协议冒号后的数据。 $.mobile.path.parseUrl() 只有一个参数 URL (string, 可选) ,其值为 一个 URL 的相对或绝对形式。 另外,$.mobile.path.parseUrl() 会返回一个包含 URL 相关成分的对象, 这个对象的属性是模仿浏览器中的 location 对象。具体的属性如下:
? ? ? ? ? ?
hash URL 中的一个部分,从 URL 中第一个 "#" 开始的部分。 host URL 的主机名及端口。 hostname URL 的主机名。 href 被解析的原始 URL 。 pathname URL 所引用的文件或目录的路径。 port URL 中指定的端口。 大多数 URLs 依赖于数据传输协议所用的默认端 口,所以这个值在大多数时候都可能是空字符串。
? ?
protocol 数据传输协议,URL 中 ':' 之前的部分。 search URL 中的从 "?" 字符开始的部分,代表 URL 查询。另外它也包括 提供给入口的额外成分,如一些常见形式的开发者访问。
? ? ? ? ? ?
authority URL 的用户名,密码,主机名 directory pathname 中的目录部分,并且不包括任何文件名。 domain URL 中的数据传输协议和用户名,密码,主机名等信息,即域。 filename pathname 中的文件部分,并且不包括任何目录名。 hrefNoHash 从原始 URL 中减去 hash 部分。 hrefNoSearch 从原始 URL 中减去 hash 和 search 部分。
69
? ?
password authority 中的 password 部分。 username authority 中的 username 部分。
例子:
// 解析一个 URL var obj = $.mobile.path.parseUrl(":password@mycompany.com:8080/mail/inbox? msg=1234"); // 解析这个 URL 会返回一个包含以下属性的对象 // obj.href: :password@mycompany.com:8080/mail/inbox?msg=1234&type=
unread#msg-content // obj.hrefNoHash: :password@mycompany.com:8080/mail/inbox?msg=1234&t ype=unread // obj.hrefNoSearch: :password@mycompany.com:8080/mail/inbox // obj.domain: // obj.protocol: :password@mycompany.com:8080 http:
// obj.authority: jblas:password@mycompany.com:8080 // obj.username: // obj.password: // obj.host: jblas password
mycompany.com:8080 mycompany.com
// obj.hostname: // obj.port:
8080 /mail/inbox
// obj.pathname:
// obj.directory: /mail/ // obj.filename: // obj.search: // obj.hash: inbox ?msg=1234&type=unread #msg-content
11. $.mobile.path.makePathAbsolute()
把一个相对的文件或目录路径转化为绝对路径。
70
具有两个参数 relPath (string, 必须) 和 absPath (string, 必须) ,具体如下:
—— relPath (string, 必须) 其值为一个相对的文件或目录路径。 —— absPath (string, 必须)
用于解析的一个绝对的文件或相对的路径。 $.mobile.path.makePathAbsolute() 会返回一个包含相对路径的绝对路径版本的字符 串。 例子:
// 返回: /a/b/c/file.html var absPath = $.mobile.path.makePathAbsolute("file.html", "/a/b/c/bar.html"); // 返回: /a/foo/file.html var absPath = $.mobile.path.makePathAbsolute("../../foo/file.html", "/a/b/c/bar.html");
12. $.mobile.path.makeUrlAbsolute()
把一个相对 URL 转化为绝对 URL 。 具有两个参数 relUrl (string, 必选) 和 absUrl (string, 必选) ,具体如下: —— relUrl (string, 必选) 一个相对形式的 URL 。 —— absUrl (string, 必选)
用于解析的一个绝对的文件或相对的路径。 $.mobile.path.makeUrlAbsolute() 会返回 一个包含相对 URL 的绝对 URL 版本的字符串。 例子:
// 返回: var absUrl = $.mobile.path.makeUrlAbsolute("file.html", ""); // 返回:
71
var absUrl = $.mobile.path.makeUrlAbsolute("../../foo/file.html", " html"); // 返回: var absUrl = $.mobile.path.makeUrlAbsolute("//foo.com/bar/file.html", " c/test.html"); // 返回: ?a=1&b=2 var absUrl = $.mobile.path.makeUrlAbsolute("?a=1&b=2", "");
// 返回: #bar var absUrl = $.mobile.path.makeUrlAbsolute("#bar", "");
13. $.mobile.path.isSameDomain()
比较两个 URL 的域。 具有两个参数 url1 (string, 可选) 和 url2 (string, 可选) 具体情况如下: —— url1 (string, 可选) 一个相对 URL。 —— url2 (string, 可选) url2 (string, required) 一个需要解析的绝对 URL 。 返回值为 boolean 型变量,若两个域匹配,则返回 "true" ,否则返回 "false" 。 例子: // 返回: true var same = $.mobile.path.isSameDomain("", " t.html"); // 返回: false var same = $.mobile.path.isSameDomain("file://foo.com/a/file.html", " .html"); // 返回: false var same = $.mobile.path.isSameDomain("https://foo.com/a/file.html", " st.html");
72
// 返回: false var same = $.mobile.path.isSameDomain("", " t.html");
14. $.mobile.path.isRelativeUrl()
判断一个 URL 是否是相对 URL 。 它具有一个参数 URL (string, 必选) ,其值为一个相对或绝对的 URL 。 返回值为 boolean 型变量,若 URL 为相对形式的 URL ,则返回 "true" ,否则返回 "false" 。 例子: // 返回: false var isRel = $.mobile.path.isRelativeUrl(""); // 返回: true var isRel = $.mobile.path.isRelativeUrl("//foo.com/a/file.html"); // 返回: true var isRel = $.mobile.path.isRelativeUrl("/a/file.html"); // 返回: true var isRel = $.mobile.path.isRelativeUrl("file.html"); // 返回: true var isRel = $.mobile.path.isRelativeUrl("?a=1&b=2"); // 返回: true var isRel = $.mobile.path.isRelativeUrl("#foo");
15. $.mobile.path.isAbsoluteUrl()
判断一个 URL 是否是绝对 URL 。 它具有一个参数 URL (string, 必选) ,其值为一个相对或绝对的 URL 。 返回值为 boolean 型变量,若 URL 为绝对形式的 URL ,则返回 "true" ,否则返回 "false" 。 例子: // 返回: true
73
var isAbs = $.mobile.path.isAbsoluteUrl(""); // 返回: false var isAbs = $.mobile.path.isAbsoluteUrl("//foo.com/a/file.html"); // 返回: false var isAbs = $.mobile.path.isAbsoluteUrl("/a/file.html"); // 返回: false var isAbs = $.mobile.path.isAbsoluteUrl("file.html"); // 返回: false var isAbs = $.mobile.path.isAbsoluteUrl("?a=1&b=2"); // 返回: false var isAbs = $.mobile.path.isAbsoluteUrl("#foo");
16. $.mobile.path.get() 该方法可以判断一个 URL 的目录部分。如果 URL 末尾没有反斜杠,则 URL 最后的部分会被认为是文件名。这个情况对于站长来说应该不陌生,如 ,URL 中最后的部分 "aaa/" 应该是一个目录,而 中最后的部分 "xxx.zip" 则应该是一个文 件名。这也是 Kayo 之前建议注意网址末尾是否需要添加反斜杠的原因。 这个方法具有一个参数 url (string, 必选) ,其值是一个相对或绝对的 URL 。返回值为 URL 中的目录部分。例子:
// 返回: var dirName = $.mobile.path.get(""); // 返回: var dirName = $.mobile.path.get(""); // 返回: var dirName = $.mobile.path.get(""); // 返回: //foo.com/a/ var dirName = $.mobile.path.get("//foo.com/a/file.html");
74
// 返回: /a/ var dirName = $.mobile.path.get("/a/file.html"); // 返回: "" var dirName = $.mobile.path.get("file.html"); // 返回: / var dirName = $.mobile.path.get("/file.html"); // 返回: ?a=1&b=2 var dirName = $.mobile.path.get("?a=1&b=2"); // 返回: foo var dirName = $.mobile.path.isAbsoluteUrl("#foo");
17. $.mobile.base
获取根元素。
18. $.mobile.silentScroll()
静默滚动到某个 Y 值处,并且不触发任何事件。 它具有一个参数,yPos (number, 默认为 0),其值为需要滚动到的 Y 位置。
19. $.mobile.activePage
引用当前激活的页面。
十二、
关于方法的调用
1. 方法调用相应 JavaScript 的引入
在介绍自定义 jQuery Mobile 默认配置时,曾经说明了相应的 JavaScript 语句需要 放置在 jQuery 库和 jQuery Mobile 库之间,而 jQuery Mobile 方法是对 jQuery Mobile 的调用,因此需要在引入 jQuery Mobile 库之后调用,具体如下:
<script src="jquery.min.js"></script> <!-- 引入自定义 jQuery Mobile 默认配置相应的 JavaScript --> <script src="custom-mobile.js"></script> <script src="jquery-mobile.min.js"></script>
75
<!-- 引入 jQuery Mobile 的调用,包括 jQuery Mobile 的方法、事件检测等全部应用 性 JavaScript --> <script src="my-site.js"></script>
2. 方法的调用
对于 jQuery 开发者,应该比较习惯在触发 ready 事件后执行 JavaScript ,例如: $(document).ready(function(){ // 执行 JavaScript }); 或简写为, $(function(){ // 执行 JavaScript });
这里说明一下,当 DOM 已经加载,并且页面(包括图像)已经完全呈现出时, 会触发 ready 事件。pageinit 事件,它在 DOM 加载完成后(包括 jQuery Mobile 对元素的 DOM 增强),就会触发,即它比 ready 更早的触发。 但由于 jQuery Mobile 驱动的网站由 Ajax 导航,因此即使一个文档中包 含多个 'page' ,当第一个 'page' 的 DOM 和内容加载完毕后就会触发 ready 事件,而 pageint 也只需第一个 'page' 的 DOM 加载完毕后即触发。 而最终利用那种事件作为开始调用方法的合适时机,会涉及很多方便的考虑, 开发者应该根据实际情况作出选择。 下面例举一个例子说明如何调用 jQuery Mobile 方法,由于 jQuery Mobile 的方法很多,这里只使用 $.mobile.changePage() 方法演示如何调用方法。例 子中的 JavaScript 代码如下:
$(function(){ $("#home").bind('swipeleft', function(){ $.mobile.changePage('./page-2.html', { transition: "slide", role: "dialog"
76
}); }); });
上例中通过检测向左划动事件触发跳转到一个外部页面,同时使用 'slide' 转 场动画并以对话框形式显示新页面。 在这个例子中,并不适合利用 pageinit 事件,下面再放上一个 Demo ,其内容 与上例大致相同,只是利用的 pageinit 事件,读者可以测试这个 Demo ,可能 会发生不断在两个页面往复来回的问题。这是因为,从第二页返回第一页并触发 pageinit 事件时,第一页的 DOM 已加载完毕,包括 JavaScript 语句,但页面 过场并未开始,这时页面再直接滑动,可能会重新触发 swipeleft 事件,于是 不断往复。因此,在使用 pageinit 事件时需要考虑 jQuery Mobile 中其他事 件、方法之间的互相影响。
十三、
jQuery Mobile 与响应式
jQuery Mobile 在刚推出的时候,曾经宣传了几个重要的特点,除了“触摸屏优 化”外,另外一个最直接的特点就是“响应式设计”,关于响应式设计,本文要 介绍的,是 jQuery Mobile 中为响应式设计作出的优化和工具。 在 jQuery Mobile 测试版本的文档中,有一个栏目名为“Responsive Layout Helpers”,即响应式布局助手,但在正式版的文档中,却删去了这个栏 目, 但这并不意味着 jQuery Mobile 削减了对响应式设计的支持, 相反, jQuery Mobile 对响应式设计有着更好的支持,而且这种支持是融入到 jQuery Mobile 的设计中,并不完全依靠开发者调用工具来调整网页达到完善的响应式布局。
1. Media Queries
在 jQuery Mobile 的 CSS 源码中,会有大量类似下面的代码:
@media only only screen screen and and (-webkit-min-device-pixel-ratio: (min--moz-device-pixel-ratio:
77
1.5),
1.5),
only
screen
and
(min-resolution:
240dpi)
{ .ui-icon-arrow-r, .ui-icon-check
.ui-icon-plus, .ui-icon-minus, .ui-icon-arrow-l, , .ui-icon-gear, .ui-icon-refresh, .ui-icon-grid, .ui-icon-star, on-home, .ui-icon-search, { background-image: -o-background-size: background-size: } .ui-icon-alt } } { background-image: .ui-icon-checkbox-off, -icon-radio-on
.ui-icon-delete,
.ui-icon-arrow-u,
.ui-icon-arrow-d,
.ui-icon-forward,
.ui-icon-back,
.ui-icon-alert,
.ui-icon-info, .ui-ic .ui
.ui-icon-searchfield:after, .ui-icon-checkbox-on, .ui-icon-radio-off,
url(images/icons-36-white.png); 776px 18px; 18px; 776px 18px; 18px; 776px
-moz-background-size:
-webkit-background-size: 776px
url(images/icons-36-black.png);
这是 Media Queries ,可以根据条件匹配相应的 CSS ,这样在不同的情况下 可以应用相应的 CSS ,以达到自适应的效果另外,jQuery Mobile 默认会对组 件进行结构、样式和交互上的增强,因此除了使用 Media Queries 为不同的情 况匹配相应的 CSS 外,jQuery Mobile 在设计增强的组件结构时也针对响应式 布局进行设计,使到由 jQuery Mobile 驱动的 Web Apps 在外观上可以更加灵 活。
2. 运行媒介查询 (Running Media Queries)
运行媒介查询 (Running Media Queries) 是 jQuery Mobile 的一个实用工具, 它在 jQuery Mobile 内部有多次调用,主要是确保一些效果能够在合适的情况 下运行。例如:在介绍 jQuery Mobile 页面转场时,有说明过,当转场页面的 宽度过大时,翻转等 3D 效果可能会过度消耗系统资源,因此开发者可以使用 $.mobile.maxTransitionWidth 控制转场最大宽度, 超过该宽度则不使用转场动 画, 而判断宽度是否超过设定值的技术原理就是利用运行媒介查询。 作为开发者,
78
我们也可以利用则个工具帮助我们 进行响应式设计,这里需要明确一点,这个 工具的作用是判断当前情况是否已经满足一个 Media Queries ,即使用 JavaScript 判断 Media Queries 内的条件是否满足。如果你已经了解了第一部 分的内容,会了解到在开发中可以根据 Media Queries 的结果判断是否应该引 入一段 CSS ,但网页布局中有时候也需要判断是否引入 JavaScript ,运行媒 介查询正是可以用于判断是否应该引入一段 JavaScript 。
例如:
$.mobile.media('screen') // $.mobile.media('screen 为 'screen' 测试是否为 // if( $.mobile.media('@media webkit and 测试媒体类型是否为 (min-width: and '480px' (-webkit-min-device-pixel-ratio: 2x (可以用来判断是否为 2)') // iPhone 4) 'screen' // 测试媒体类型是否
480px)')
并且窗口宽度大于等于 screen
内核并且像素比为
根据判断结果作出相应的处理 $.mobile.media('screen // 相应的处理 and (min-width: 480px)') )
3. 设备方向变化事件与方向类
当设备方向变化(即设备在横向和纵向的方向间转变)时,会触发 orientationchange 事件, 这个事件的回调函数的事件对象(e 或 event)中会封 装一个 orientation 属性, 其值为 "portrait" 或 "landscape" ,用来描述设 备是改变为纵向时触发事件还是改变为横向时触发事件。在旧版本的 jQuery Mobile , 这个值也会作为 class 添加到 html 标签中,让开发者可以依据这个 class 添加相应的 css ,即方向类,但在新版的文档中已经没有关于方向类的 说明,Kayo 调试后也没有出现相应的方向类,因此在新版 jQuery Mobile 中已 经不支持原生方向类,但可以通过 jQuery 达到相同的效果,例如:
$(window).bind( if( else });
79
'orientationchange', ==
function(e){ ) $('html').addClass('portrait').r ) $('html').addClass('lands
e.orientation if(
'portrait' ==
emoveClass('landscape'); e.orientation 'landscape' cape').removeClass('portrait');
分别为 landscape 和 portrait 指定相应的样式即可。 另外,关于 orientationchange 事件的绑定元素和不支持该事件时的处理也需要特别 注意,具体可以参考 —— 《使用 jQuery Mobile 与 HTML5 开发 Web App —— jQuery Mobile 事件详解》的第三部分“设备方向变化事件 (Orientation change event)”。
十四、
HTML5 Web Storage
绝大多数的软件都需要使用某种具有持久性的方式来存储数据,Web Apps 也不 例外,涉及到完整后台的 Web Apps ,可以直接在后台使用 mysql 等数据库来 存储数据,但过多的 sql 查询会影响服务器性能,甚至是整个 App 的性能。因 此,一些简单有效的存储方式对与 Web Apps 显得很重要,Web Storage 似乎正 是为此而设计。下面开始正式介绍 Web Storage 。
1. Web Storage 是什么?
Web Storage 是 HTML5 中用于在客户端存储数据的方法,有两种形式: localStorage(本地存储)和 sessionStorage(会话存储)。这两种方法都允 许使用 JavaScript 设置“键值对”,并保存在客户端中,在重新加载页面时读 出它们。 熟悉 Web 开发的读者会发现, 这与 cookie 的机制很相似, 但与 cookie 相比,它们有很大的差异:
cookie
cookie 不适合大量数据的存储,因为它们由每个对服务器的请求来传递,这使得 cookie 速度很慢而且效率也不高。
Web Storage
Web Storage 的数据完全存储在客户端,不需要通过浏览器的请求再传输到服务器,这 样不但可以存储更多的数据,速度也较快。并且,Web Storage 具有统一的编程接口, 使得数据操作更为简便。
2. localStorage(本地存储)和 sessionStorage(会话存储)
80
上面有提及,Web Storage 有 localStorage 和 sessionStorage 两种形式,它 们在功能上是一样的,只是持久性和范围有所不同,具体如下:
1. localStorage
localStorage 方式存储的数据没有时间限制,即使浏览窗口关闭了,数据也会 保存下来,这些数据也可用于所有来自同源(即域名,协议和端口均要相同)窗 口(或者标签页)的加载,实际开发中用于 Web Apps 的选项设置或用户偏好设 置会很有用。
2. sessionStorage
sessionStorage 方式存储的数据实际上存储在窗口对象中,当关闭浏览器窗口 后,数据会被删除。由于这些数据是存储于窗口对象中,所以它们对于其他窗口 或标签页不可见。实际开发中可以用于记录暂时的状态或排序。
3. 浏览器支持
关于浏览器对 Web Storage 的支持情况需要分开 API 和事件两个方面进行说明
API 支持情况
IE8+ ,Chrome 4+ , Firefox 3.5+ , Safari 4+ 和 Opera 10.5+ 对于 Web Storage API 有良好及基本统一的支持, 事件支持情况 相对于 API ,Storage 的事件比较晚才有良好的浏览器支持,具体如下:Firefox 5+ , Safari 5+ , Chrome 12+ , Opera 10.5 + 和 IE9+
4. 使用 Web Storage API
下面会例举一些例子说明如何设置、访问和删除 Web Storage 。例子中会统一 使用 localStorage ,但实际上在这些例子中使用 localStorage 或 sessionStorage 并没有区别,不过读者需要注意 sessionStorage 在关闭窗口 或标签页后会丢失。
81
但在之前 Kayo 需要说明一点,对于不同的域(包括子域),Web Storage 的数 据存储于不同的区域,并且一个网站只能访问其自身的数据。这也是 localStorage 只能访问同源窗口或标签页的原因。
设置
localStorage.setItem('username', 'Kayo'); // 设置 username 为 Kayo
访问
var username = localStorage.getItem('Kayo'); // 访问 username 并把其键值存储在一个变 量 username 中
删除
localStorage.removeItem('username'); // 删除 username 键
以上是标准的 Web Storage 基本操作,实际上还有另外一系列更实用的操作方式,假 如开发者的键是有效的 JavaScript token (即没有空格、 没有除下划线之外的标点) , 那么可以使用如下的操作方式:
Js 代码 1. localStorage.username = 'Kayo'; // 设置 username 为 Kayo 2. var username = localStorage.username; // 访问 username 并把其键值存储在一个变 量 username 中 3. delete localStorage.username; // 删除 username 键
由于 Web Storage 的操作基于 JavaScript ,因此 Kayo 建议使用第二种操作方式, 这样会更加方便并且利于整段 JavaScript 代码的阅读。
除了上面三种基本操作外,Web Storage 还包括一个 length 属性以及以下两个方法:
clear()
清空一个域下的全部键值。
82
key(n)
返回一个域下 localStorage 列表或 sessionStorage 列表的第 n 个键的键名。
length
返回一个域下 localStorage 列表或 sessionStorage 列表的键的总数。
5. 实例
在说明了 Web Storage 的基本使用后, 下面举例说明 Web Storage 的具体使用。 Web Storage 虽然相对 cookie 可以存储更大的数据量,但这里的更大只是数据 的大小,由于 Web Storage 采用的是“键值对”的存储方式,即一个“键名” 对应一个值,这样并不利于处理大量的数据,因此 Web Storage 更适合存储辅 助性的数据, 尤其是处理大量相同性质的数据时, Web Storage 便显得很不灵活。 在例子中,Kayo 会以大家比较熟悉的保存用户留言信息进行说明,即使用 Web Storage 代替大家熟悉的 cookie 记录用户留言信息。 例子中会有一个表单, 填入表单的内容并提交,但这里会阻止默认的表单提 交动作,改以存储在 localStorage ,为了方便操作,会把设置、访问键值写成 独立的函数,具体的情况可以测试完整 Demo (为了简化例子结构,这里只使用 addEventListener 监听事件,请使用 Chrome, Firefox 等现代浏览器浏览 Demo ,下同)。测试方法:填写相关信息,提交表单,刷新页面,观察用户信 息部分是否得到保留,为了更容易理解 Web Storage 的使用,例子中并没有制 作相应的后台,并且由于阻止了表单提交,提交表单不会出现反馈,因此提交表 单后直接刷新页面即可。下面列出例子中主要的代码。 主要 HTML 结构
<form action="" id="add-comment" name="add-comment" /> <h1>发表评论</h1> <div id="userinfo"> <div class="item"> <span>用户名: </span> <input type="text" name="username" id="username" />
83
</div> <div class="item"> <span>E-mail: </span> <input type="email" name="email" id="email" /> </div> <div class="item"> <span>网址: </span> <input type="text" name="website" id="website" /> </div> </div> <div class="item"> <span>评论: </span> <textarea name="comment" id="comment" cols="33" rows="8"></textarea> </div> <div id="submit-info"> <input type="submit" value="发表"> </div> </form> JavaScript 代码 var username = document.getElementById('username'), email = document.getElementById('email'), website = document.getElementById('website'), submit = document.getElementById('submit'); // 加载已保存的 localStorage function loadUserInfo(){ username.value = localStorage.username; email.value = localStorage.email; website.value = localStorage.website; } // 存储表单数据为 localStorage function saveUserInfo(){ localStorage.username = username.value; localStorage.email = email.value; localStorage.website = website.value; } // 打开页面时加载数据 loadUserInfo(); // 使用存储表单数据为 localStorage 代替表单提交 submit.addEventListener('click', function(e){ e.preventDefault();
84
saveUserInfo(); });
从代码量上看,由于例子比较简单,因此这并不会比 cookie 版的代码量少,但结构却 简洁很多,并且操作方式很简单,即使增加更多的信息项也很方便。
6. Web Storage 事件
Web Storage 支持一个 "storage" 事件,Web Storage 中的数据被保存后,修 改或删除, 都会触发 storage 事件。 但由于浏览器对于该事件的支持并不完善, 因此实际上在大多浏览器中,"storage" 并没有完全按照上面所说的触发。在介 绍 "storage" 事件的实际效果时,Kayo 先介绍一下该事件的具体情况。 "storage" 事件会把一系列的属性封装在相应的 event 对象中,用于绑定事件 回调函数内部调用,具体的属性如下:
? ? ? ? ?
key 返回发生变化的 key (即键名) oldValue 返回发生变化的 key 的原值(即改变前的值) newValue 返回发生变化的 key 的新值(即改变后的值) url 返回触发事件的 URL storageArea 返回触发事件的对象
这里需要提醒一点,Storage 的 事件需要在带有域名的目录下才能触发,即需 要 Web 服务的支持,直接打开相应的文件并不能触发 Storage 事件,而 Storage 的 API 则无须这样。 接下来对上面的例子进行扩展,监听其中的 Web Storage ,你可以点击下 面的 Demo 进行测试。 这里问题就会出现了, 在 Chrome 22 , Firefox 16 , Safari 5.1 中,直接改变表单中的值并提交是不会触发 "storage" 事件,但当用户打 开两个 Demo 标签, 改变其中一个标签中表单的值并提交,另一个页面反而会触 发事件。 事实上在较低版本的这三款浏览器中也会出现这个情况,这似乎是这三
85
款浏览器对于 Web Storage 的处理机制并不完善。也因为这样,Kayo 并不建议 在实际开发中利用 "storage" 事件。监听 storage 事件
function triggerEvent(e){ var tips = 'key:' + e.key + ', newValue:' + e.newValue + ', oldValue:' + e.oldValue + ', u rl:' + e.url + ', storageArea:' + e.storageArea; alert(tips); } window.addEventListener('storage', triggerEvent, true);
7. 不足之处
Web Storage 虽然功能强大并且使用也很方便,但实际上它仍存在一些问题,除了上面 有提及的浏览器支持仍存在不足外,安全问题也是开发者必须注意的重要问题。W3C 为 开发者列出了以下三点安全问题:
DNS 欺骗攻击 (DNS spoofing attacks) 因为一些潜在的 DNS 欺骗攻击,Web Storage 无法保证发出请求的脚本所在域 是当前的域,这意味着域 A 中嵌入域 B 的脚本,该脚本可以访问域 A 的 Web Storage 。为了尽量减轻这种情况发生,可以使用对页面 TLS 。使用 TLS 可以 确保用户或软件代表真实使用者, 这样其他页面需要使用能确定它们来自同一域 的 TLS 证书才可以访问 storage 。 跨目录攻击 (Cross-directory attacks) 若不同的用户共享使用一个域名,例如几位用户共用 abc.com 域名,所有人都 将会共享 abc.com 下的 storage 对象, 但没有任何特性可以限制特定访问路径。 因此不建议共享域名的用户使用 Web Storage ,这样可以避免域名下的其他用 户可以阅读你的 Web Storage 甚至重写它们。
86
即使可以限制访问的路径,也可以利用 DOM 脚本安全模型轻松地跳过这保护并 访问数据。当然,Web Storage 是存储在本地端,如果这些共享域名的用户之间 不会接触到其他人的本地端,那这个问题就不用担心了。 实施风险 (Implementation risks) 当使用这些持久化存储特性时, 会让有不好意图的网站跨域阅读到这些数据,甚 至还会让这些网站写入信息,然后再跨域利用这些信息。 直白的说,让第三方网站写入持久性的数据可能会导致信息泄漏,例如:一个 域上的一个用户购买清单可以被另一个域作为定向广告。 最后关于兼容性的问题,由于移动端上的主流浏览器(Android, IOS 的系 统浏览器, opera 等现代浏览器)对于 Web Storage 乃至很多 HTML5 的特性支 持已经很完善和统一,如果你是利用这项特性开发 Web Apps ,兼容性的问题反 而不用过于担心,这也是使用 HTML5 开发 Web Apps 的重要优势。 因此,虽然 Web Storage 仍会存在一些不足,但从综合的角度考虑,Web Storage 已经具有很好的实用价值。利用 Web Storage 保存一些非机密的设置 信息无疑是 Web Apps 开发中一个很好的选择。
十五、
HTML5 离线缓存
本文要介绍的,是 HTML5 离线网络应用程序的特性,离线网络应用程序在 W3C 中的实际名称是 "Offline Web applications" ,也称离线缓存。当用户打开浏 览器时, 浏览器会将一个列表中指定的资源都下载并储存在本地。下次当用户再 访问这个网络程序时,浏览器会自动引用本地缓存中 相应的文件,而不会再从 网络下载这些资源。不管离线网络应用程序是否专为 Web Apps 而设,但这对于 Web Apps 来说无疑是个非常实用的特性, 它使到 Web Apps 相对于原生 Apps 的 一个重要劣势 —— 高度依赖网络,得以大大减缓。开发者可以利用这个特性把 Web Apps 中的元素缓存到本地端,使到 Web Apps 可以脱机工作,即使是需要
87
联网工作的 Apps ,也可以缓存部分文件到本地端,减少带宽占用,这样 Web Apps 相对于原生 Apps 就更加具有优势了。下面正式开始介绍这个特性。 1. 离线网络应用程序基础
离线网络应用程序的核心是一个 content type (内容类型) 为 cache-manifest 的文本文 件。这个文件保存了应用程序中需要离线存储的文件(HTML, CSS, JavaScript, 图片等)。 举一个简单的例子,若一个应用程序由以下文件组成:
? ? ? ?
index.html demo.css demo.js logo.png
index.html 为主页, 其他文件是主页中引用的资源, 如果我们需要离线缓存这个应用程序, 需要在 index.html 的同级目录下增加一个 manifest 文件,并命名为 .manifest 后缀文 件,而文件中的内容可以这样编写: CACHE MANIFEST ./index.html ./demo.css ./demo.js ./logo.png
可以看出,以上文件的路径是相对路径,这里是相对于 manifest 文件而言的。 当然,你也可以使用绝对路径,这并不影响 manifest 的使用。 manifest 文件的编写很简单,但启用离线缓存还需一些步骤。首先是需要把 manifest 文件和应用程序关联起来, 即把页面指向缓存名单, 方法是为 html 标 签指定 manifest 值,例如:
<html manifest="demo.manifest">
88
其中 demo.manifest 是例子中编写的 manifest 列表文件。 小提示:若应用程序中有多个页面,则每个页面都需要与 manifest 关联起来。 接着,开发者必须给 manifest 文件指定 text/cache-manifest 内容类型,这样浏览 器才能识别它。 关于具体的方法, 如果你的服务器支持 .htaccess , 可以在 .htaccess 中写入以下语句:
AddType text/cache-manifest .manifest
这样做可以把 text/cache-manifest 的 MIME 类型和 .manifest 文件关联起 来。当然,可能开发者并没有 .htaccess 的编写权限,但实际上,开发者可以 使用另外一些更实用的方法达到目的。因为在实际的项目开发中,应用程序中的 文件数量不会只像上例中仅有的 4 个,如果有很多的文件需要缓存,每个文件 都需要手动写入 manifest 文件实在比较费时,更麻烦的是,每次改动这些文件 都必须相应地改动 manifest 文件, 因此 Kayo 更加建议开发者使用后台脚本直 接获取需要缓存的文件并写入一个 manifest 列表,Kayo 熟悉的后台脚本是 PHP , 在 PHP 中, 可以直接在代码中设置 MIME 类型, 这样就不需要配置 Web 服 务来完成对 manifest 的支持了。至于具体如何使用 PHP 编写 manifest ,会 在下面详细介绍。 2. 浏览器支持
关于离线网络应用程序在现代浏览器中都已经实现完整的支持,IE 则完全不支持。具体如 下: Chrome 4+ , Firefox 3.5+ , Safari 4+ 和 Opera 10.6+
3. 白名单 默认情况下,开发者会为应用程序中所有文件指定缓存,但实际上,仍有一些资 源可能需要强制取消缓存, 即必须访问网络资源, 离线时该资源不可用。 为元 素 强制取消缓存可以在 manifest 文件中使用关键字 NETWORK: 。 在 NETWORK: 关 键字下添加文件的列表, 这些文件会强制取消缓存,而这个文件列表就称为白名 单 (Whitelist) 。实际上,对于需要缓存的资源也是有关键字的,这个关键字
89
是 EXPLICIT: ,但所有资源列表的开头如果没有添加关键字,默认都会被认为 在 EXPLICIT: 关键字的列表下,因此需要缓存的资源列表开头可以忽略不写关 键字(如上例)。例如,对上例进行扩展,把 logo.png 添加到白名单,可以这 样编写 manifest 文件。
1. 2. 3. 4. 5. 6. 7. CACHE MANIFEST ./index.html ./demo.css ./demo.js NETWORK: ./logo.png
4. 备选名单 备选名单是对于白名单的补充,在白名单中,没有联网时,资源不能加载,这样 会导致页面出现错误,如上例中,"logo.png" 被设置为白名单,如果用户离线 浏览该应用程序,会出现一个损坏的图片链接,为了避免这种情况,可以使用 FALLBACK: 指定一个备选名单, 备选名单中需要为一个资源准备两个文件,若能 正常联网,会引用第一个文件,离线时则引用第二个文件,关于这个特点,有一 个很实用的应用 —— 表明程序是离线工作还是联网工作, 在不同的状态下引用 不同的图片即可方便地表明状态。接下来 Kayo 继续扩展上例,为 logo.png 指 定一个离线时的替换图片 backup.png 。
1. 2. 3. 4. 5. 6. 7. CACHE MANIFEST ./index.html ./demo.css ./demo.js FALLBACK: ./logo.png ./backup.png
5. 更新 manifest 似乎,经过上面三个步骤后,应用程序的离线缓存已经很好的工作了。但有一个 很重要的问题仍需注意 —— 根据离线缓存的工作原理, 当用户第一次使用应用 程序时, 浏览器会根据 manifest 文件里的列表下载指定的资源,在下次使用该
90
应用程序时,浏览器会自动加载这些资源的副本,那么假如开发者修改了程序, 浏览器仍旧会加载本地的资源,因此我 们需要给浏览器一个提示,程序已经更 新。 那么什么时候浏览器会更新本地缓存呢? 只有当 manifest 修改后浏览器才会重新下载 manifest 中所有指定需要离线 缓存的文件。 而检测 manifest 是否修改过是对 manifest 文件的内容逐个字符 进行比较,包括注释和空行。当然,大多情况下,修改程序时并不会影响主要的 文件, 所以 manifest 中的文件列表也不会有改动,因此需要改动 manifest 以 通知浏览器程序已更新的最好办法是修改注释, 开发者可以在 manifest 文件中 添加一行注释, 比如说是程序的版本号,当程序更新后同时修改 manifest 文件 中这个版本号, 浏览器就会判定程序已经更新,自动重新下载所有需要离线缓存 的资源。例如,把上例改成:
C 代码 1. 2. 3. 4. 5. 6. 7. 8. CACHE MANIFEST # version 1.0 ./index.html ./demo.css ./demo.js FALLBACK: ./logo.png ./backup.png
需要注意的是,"CACHE MANIFEST"是必要行,并且必须在 manifest 文件中的第 一行。 这样下次更改程序后同时修改 manifest 的程序版本号,浏览器就可以判 定程序更新了。 手动更新缓存 当然,为了能更精确地控制程序更新,最好是使用手动方法更新缓存,离线网络 应用程序规范中也提供了相应的手动更新缓存的方法。开发者可以使用 window.applicationCache.update() 方法手动更新缓存,为了更准确地判断是
91
否需要更新, 开发者可以先检测 window.applicationCache.status 的值,若其 值为 "UPDATEREADY" (即浏览器检测到 manifest 已被修改), 可以调用 window.applicationCache.update() 方法更新缓存。例如:
1. if ( window.applicationCache.status == window.applicationCache.UPDATEREADY ){ 2. window.applicationCache.update(); 3. }
6. 使用 PHP 脚本编写 manifest 文件 如上面所说, 使用脚本编写 manifest 文件可以同时解决 manifest 文件扩展名 与 MIME 类型关联起来,还可以自动列出缓存文件。具体的编写如下:
header('Content-Type: text/cache-manifest'); echo "CACHE MANIFEST\n"; $allHashes = ""; // 创建一个字符串保存文件的 md5 值 $dir = new RecursiveDirectoryIterator("."); foreach(new RecursiveIteratorIterator($dir) as $file){ // 获取当前目录并遍历文件 if( $file->IsFile() && // 判断获取内容为文件 $file->getFilename() != "manifest.php" && // "manifest.php" 不缓存 $file->getFilename() != "logo.png" && // 备选资源不缓存 $file->getFilename() != "offline.png" && !strpos( $file, '/.' ) && substr( $file->getFilename(), 0, 1 ) != "."){ echo "./" . $file->getFilename() . "\n"; $allHashes .= md5_file($file); // 把每一个缓存的文件的 md5 值连接起来 } } echo "FALLBACK:\n"; // 输出备选名单 echo "./logo.png ./offline.png\n"; echo "# " . md5($allHases) ."\n"; // 把连接起来的 md5 值重新计算一个 md5(因为连接所 得的字符串过于冗长)
在这个脚本中,获取了应用程序的目录并把目录中的文件逐个添加到缓存列表, 同时在这个过程中排除如 "manifest.php" 和备选资源等文件,并且,对每一个 缓存的文件计算 md5 值, 把这些值连接起来后重新计算一个 md5 并输出到一行 注释中,这样缓存的文件只要有一个发生了改变,都会影响这行注释,从而使到
92
整个 manifest 文件发生改变,这样就并不需要在更新程序后手动修改 manifest 文件。 可以看出, 如果需要缓存的文件很多时, 该方法将会十分方便, 并且更新程序后 manifest 文件也会被自动修改。当然,这只是使用脚本编写 manifest 的其中一种方式,开发者应视具体情况而制定相应的脚本。 7. 关于离线网络应用程序的属性、方法和事件 在 “手动更新缓存” 中,Kayo 提到了一个对象 window.applicationCache , 这个对象中包含了与离线网络应用程序相关的属性、方法和事件,除了上面涉及 到的 status 属性和 update() 方法外,还有其他的相关内容,下面开始对它们 进行详细介绍。 属性 window.applicationCache 对象中具有一个属性 status , 该状态会根据当前的 缓存状态显示不同的值和状态编号,具体的属性值如下:
? ? ? ? ? ?
UNCACHED 未开始缓存状态。状态编号:0 IDLE 空闭状态。状态编号:1 CHECKING 正在检查 manifest 文件是否存在。状态编号:2 DOWNLOADING 正在下载缓存文件。状态编号:3 UPDATEREADY 更新下载已完成,等待更新状态。状态编号:4 OBSOLETE 废弃状态。状态编号:5
方法
接着,是相关的方法,具体如下:
?
update()检测与文档关联的 manifest 文件是否有修改,如果有修改,则更新缓 存。 若 manifest 文件不存在或该缓存已废弃, 则会抛出一个 InvalidStateError 错 误。
?
abort() user agent 会发出一个信号给当前的缓存对象, 中止应用缓存的下载, 如 果页面没有使用离线网络应用程序,那么在尝试发出信号后该方法不会再执行 任何操作。
93
?
swapCache()手动执行本地缓存更新,并且只能在 updataReady 事件触发时在事 件回调函数中调用。但需要注意该方法不会立即更新缓存文件,仍需要刷新页 面才生效。 若文档关联的 manifest 文档不存在, 会抛出一个 InvalidStateError 错 误。
事件 除了属性和方法, window.applicationCache 对象还会根据一些情况在其身上触 发一些事件,开发者应该了解这些事件,根据所触发的事件,可以了解一个正在 运作的离线缓存的工作情况,然后根据不同的情况作出适当的处理。
?
checking 浏览器在检测到 html 标签上有 manifest 属性后,会检查相关 联的 manifest 文件是否存在,同时触发 checking 事件。
? ? ? ? ?
noupdate 在检测到 manifest 没有更新(即没有修改)时触发。 downloading 缓存下载时触发。 progress 下载进度(阶段性事件) 。 cached 已根据 manifest 文件中指定的要求下载相应的资源。 updateready 更新时, 已根据 manifest 文件中指定的要求重新下载相应的 资源。
?
obsolete manifest 文件请求发生 404 或 410 错误时触发, 发生此事件表 明该缓存已被删除。
?
error 以下四种情况都会触发 error 事件:1. manifest 文件请求发生 404 或 410 错误;2. manifest 文件没有修改, 但页面无法正确引用 manifest ; 3. 根据 manifest 文件更新资源时发生致命错误(如上面提到的 InvalidStateError 错误) ;4. 当资源正在更新时 manifest 文件被修改。
这里 Kayo 需要指出一点, 以上这些事件并不会在一个缓存过程中全部触发,如 error(前三种情况) , updateready , obsolete , noupdate , cached 均为一 个缓存过程中的最终事件,在一次缓存过程中只会出现其中一个。又如 cached 事件, 必须要有下载资源并且在完成后才触发, 即第二次打开页面并且 manifest
94
没有修改是不会触发 cached 事件(没有下载资源),开发者应仔细注意每个事 件的触发时刻,判断在不同情况下应该利用何种事件。 这个例举一个例子, 使用 addEventListener 监听 cached 事件, 检测到 cached 事件发生时弹出提示,即代表离线资源已经下载完成。
1. if(window.applicationCache) { 2. window.applicationCache.addEventListener('cached', function(){ 3. alert('cached'); 4. }, true); 5. 6. }
十六、
HTML5 Web Workers
本文要介绍的是 HTML5 的 Web Workers 特性,它解决了 JavaScript 开发中一 个重大的问题 —— 在后台运行 JavaScript 。 与本系列前两篇文章介绍的特性 相似, Web Wordkers 似乎也是为了 Web Apps 而设计的, 可以想象, Web Apps 乃 至原生 Apps 受移动设备性能的限制比在桌面环境中要大很多, 尽管现在的移动 设备性能已经不断的提高,这对于发展 Web Apps 的确是个很好的机遇,但是其 性能表现始终受限,因此,对 Web Apps 开发来说 Web Workers 无疑是个十分 实用的技术,使到 Web Apps 可以在移动设备上更好的运行。 1. 什么是 Web Workers ? 在介绍 Web Workers 的具体使用时,Kayo 首先正式说明一下 Web Workers 。 当 HTML 页面中执行 JavaScript 时,都是单线程执行的,这时页面的状态是不 可响应的,即页面的 UI 会被锁定,若执行需要的时间过长,页面甚至会出现假 死状态。 这样对于用户来说是个很不好的体验,他们只能等待 UI 恢复过来才能 继续操作,对于开发者来说,这也很无奈。Web Workers 则使到 JavaScript 能 在后台运行 ,即在后台创建相应的线程,把费时的处理交给后台,前台便能继
95
续响应用户的操作, 这样既不会影响页面的性能,又使到用户可以继续做想做的 事。可以看出,Web Workers 确实是个很棒的特性,但它仍有一些限制: Web Workers 会完全独立于它们的执行页面,即在独立线程中工作,因此不 能在 Web Workers 内访问 DOM 对象,window 对象,document 对象和 parent 对象。但 Web Workers 仍可以直接访问 navigator ,因此开发者可以访问 navigator 对象中如 appName , appVersion 和 userAgent 等一些属性。 由于这个限制的存在,我们无法直接利用 Web Workers 进行 DOM 操作,因 此 Web Workers 更适合用于复杂的计算等耗费 CPU 的处理,这样可以尽量减轻 CPU 的负担,提升应用的性能。另外,需要开发者虽然无法直接在 Web Workers 内进行 DOM 操作,但可以在 Web Workers 的 message 事件的回调函数中进行 DOM 操作(关于 message 事件 Kayo 会在下面详细介绍),而把计算处理交给 Web Workers 在后台计算。 另外,也是由于 Web Workers 在独立线程中工作的原因,因此它也不能使 用主线程中的变量和函数,也不能使用 alert 等会使到页面状态暂停的操作。 以上就是 Web Workers 的基本情况了,虽然仍有限制,但 Web Workers 已 经有很实用的开发价值了。 2. 浏览器支持 Web Workers 在现代浏览器中都已经实现完整的支持,IE 则完全不支持。具体 如下(以下版本号表明从该版本开始支持 Web Workers ,但并不一定完全支持 Web Workers 的完整功能,并且早期的具体表现在各浏览器之间有较大差异): Chrome 3+ , Firefox 3.5+ , Safari 4+ 和 Opera 10.6+ 3. 使用 Web Workers
下面开始介绍如何利用 Web Workers 在后台运行 JavaScript 脚本。
96
1)
创建 Web Workers 对象
使用 Web Workers 运行 JavaScript 必须创建一个相应的 Web Workers 对象, 例如,把需要执行的 JavaScript 都放在 demo_workers.js 中,而 demo_workers.js 与主页文档 index.html 处于同级目录,可以在 index.html 中使用以下语句创建相应的 Web Workers 对象:
var w = new Worker('demo_workers.js')
这样创建 Web Workers 对象之后,可以使用 "w" 引用这个 Web Workers 进行 其他的操作了。为了避免无效的操作,开发者还可以在创建及使用 Web Workers 之前判断浏览器是否支持 Web Wokers 。具体的代码如下:
1. if( typeof(Worker)!=="undefined" ){ 2. 3. // 创建 workers 对象 4. var w = new Worker('demo_workers.js'); 5. } else { 6. alert('抱歉,你的浏览器不支持 Web Workers!'); 7. }
2)
发送信息
在创建 Web Workers 对象后,就可以继续进一步的使用了,Web Workers 的常 用操作包括发送信息和接受信息,之所以要使用专门的方法来发送和接收信息, 是因为创建 Web Workers 对象后只会执行脚本,但无法直接与脚本互通信息, 而有了信息的传递才是真正的利用 Web Workers,下面开始介绍这两个方法。 要发送信息,可以使用 postMessage() 方法,这里值得注意的是,有些资 料介绍 postMessage() 方法是从前台发送信息到后台的方法,实际上从后台发 送信息到前台也是可以的 (甚至可以说是必须的) , 并且也是使用 postMessage() 方法,只是具体使用的情况稍有不同。从前台发送信息到后台,通常是发送需要 在 Web Workers 内部进行计算的原始数据,这需要在相应的 Web Workers 对象 上调用 postMessage() 方法, 例如发送一个字符串到上面创建的 "w" 的后台中, 可以这样编写代码:
97
1. // 定义需要发送的信息字符串 2. var the_string = "This is a message."; 3. // 发送信息到后台 4. w.postMessage(the_string);
这样一个字符串便会发送到 Web Workers 后台了,而在 Web Workers 的后台, 即上面的 "demo_workers.js" 内部,若需要发送信息(通常为 Web Workers 根 据原始数据计算的结果数据),由于 Web Workers 对象已经默认是自身对象, 因此无需再手动引用 Web Workers 对象。例如,我们需要发送一个结果字符串 到前台,可以这样编写代码:
1. //发送信息到前台 2. postMessage(result);
3)
接收信息
既然有发送信息的方法, 那么肯定也有接受信息的方法,接收信息的方法是监听 onmessage 事件, 在 onmessage 事件的回调函数中有一个封装好的参数 event , 在 event 的 data 属性中包含了使用 postMessage() 发送过来的数据。 这个接 收方法也是可以在前台和后台中使用,与 postMessage() 相似,后台监听 onmessage 事件不需引用 Web Workers 对象。 例如, 针对上面发送信息的例子, 接收相应的信息可以这样编写代码:
Js 代码 1. // 在后台中接收前台发送过来的信息 2. onmessage = function (event){ 3. // 从 event 中获取数据,在这里其值为 "This is a message." 4. var original_data = event.data; 5. // 处理数据,得到结果 6. // 发送计算结果到前台 7. postMessage(result); 8. }; 当然,你也可以使用 addEventListener 标准监听事件方法监听 onmessage ,例如: Js 代码 1. w.addEventListener('message', function(event){
98
2. // 处理数据,同上 3. }); Js 代码 1. // 在前台接收后台发送过来的信息 2. w.onmessage = function (event){ 3. // 从 event 中获取数据,在这里为 result 的值。 4. alert(event.data); 5. }; 到这里,已经完成了一个完整的 Web Workers 的基本使用过程。
4)
终止
当 Web Workers 对象被创建后,即使它执行的外部脚本已经完成,它也会继续监听信息。 若需要终止 Web Workers , 释放相应的资源, 可以使用 terminate() 方法。 例如终止 "w" , 可以这样编写代码: Js 代码 1. w.terminate()
4. 更多方法与事件 关于 Web Workers 的方法除了上面介绍到的 postMessage() 和 terminate() 外还有以下两个方法,并且以下两个方法只能在 Web Workers 执行的脚本中使 用,在上例中即只能在 demo_worker.js 文件中使用。
1) close
停止 Worker 的行为。
2)
importScripts
Workers 线程会动态加载外部脚本,调用该方法则会冻结 Worker 的线程,直到 动态加载脚本完毕或脚本执行完毕(具体视浏览器而定),该方法可以方便开发 者在 Web Workers 的脚本文件中载入其他脚本文件(例如 JavaScript 代码很 长,需要分开几个文件编写时该方法便十分有用)。由于 Web Workers 是在独
99
立线程中工作,它无法访问 document 对象,即无法访问外部资源,因此需要用 该方法载入外部脚本。另外关于 importScript 还有以下两点需要注意:
?
importScripts 支持同时加载多个脚本,只需在每个参数中填写一个 JavaScript 文件,如:importScripts('a.js', 'b.js', 'c.js');
?
只要 HTTP 连接数足够,使用 importScripts 同时加载多个脚本时均为并 行加载。但执行这些脚本是按照参数顺序进行的,如上面的例子,则按照 a.js , b.js , c.js 的顺序执行各脚本(即使 b.js 脚本比 a.js 脚本先加载完毕, 也会等待 a.js 加载完毕并且执行 a.js 后才会执行 b.js )
接下来再介绍 Web Workers 事件 onerror 。 执行 demo_workers.js 时若捕获到语法错误或运行异常(相关的文件 404 , JavaScript 错误等)会触发 onerror ,注意该事件只能在 Web Workers 前台 监听,具体的错误信息会封装在事件回调函数的 event 对象中,具体如下:
Js 代码 1. worker.onerror = function(event){ 2. 3. event.message // 具体的错误信息 4. event.lineno // 在 demo_workers.js 中导致错误发生的语句的所在行号 5. event.filename // 返回发生错误的文件的完整 URL 6. }; onerror 事件也支持使用 addEventListener 标准监听事件方法监听。
5. 其他类型的 Workers 上面介绍的是 Web Workers 的基本类型,也就是普通的 Worker ,事实上还可 以在普通的 Worker 上扩展出另外两种 Worker —— Subworker 和 Shared worker 。
100
1)
Subworker
Worker 支持在一个 Worker 内部创建 Worker , 称为 Subworker 。 这个 Worker 必须与父 Workers 同源, 它的 URL 是根据父 Worker 的 URL 确定的, 而不是依据它自己的页面 URL , 这样导致了以下两个需要注意的地方:
? ?
Subworker 不能跨域 内部 Worker 引用资源必须使用相对 URL(相对于创建父 Worker 的页面,即上例 中的 index.html) 。
2)
Shared Worker
开发者也可以创建一个被多个页面或连接使用的 Worker ,称为 Shared Worker(共享 Worker ),可以用于页面之间的共享通讯,它的工作方式与普通 Worker 稍有不同,目前 主流浏览器对其支持都很不完善,因此这里不作详细介绍。
6. 其他注意事项
1) 可用的常用方法
在文章第一部分中,有介绍到由于 Web Workers 是在独立线程上工作,因此产生了无法直 接访问 window 对象等一些限制, 但这不影响 JavaScript 的大多数使用技巧, 包括数据的 类型和大多数方法(包括在 window 对象上的 setTimeout() 和 setInterval() 方法)都 不受影响。
2)
postMessage 中可用的数据类型
虽然 postMessage 中使用的数据类型并没有严格限制, 但考虑到 postMessage 用于线程间 的(即 Web Workers 中的线程与主页面的线程,或是多个有关联的 Web Workers 之间的线 程)交互,因此建议使用 JavaScript 本地数据类型,如 Array , String , Date , Math , 同时也支持 JSON ,而不建议使用较为复杂的自定义类型。
3)
location 对象的访问
Web Workers 可以访问 location 对象, 但只可以以只读方式访问。 开发者可以从 location 对象中获取 hostname 和 port 的值。 在下面的例子中,可以让用户输入两个整数,并计算它们的最大公约数和最小公倍数, 计算方法采用递归算法,计算的部分写在独立的脚本文件中并交给 Web Workers 计算,建 议用户输入数值较大的数据进行测试。 当然, 这个例子的主要意义只是演示 Web Workers 的 使用方法, 由于现在的桌面环境乃至移动设备环境都有了很大的提升, 因此像例子中的算法 即使使用大数值的数据进行测试也未必能体现 Web Workers 的优势,但在实际的 Web Apps
101
开发中, 却很可能会出现比这个算法复杂得多的情况, 例如从数据库中获取大量数据并运算, 涉及物理模拟的运算,或是多个复杂算法需要并行运算,这样的情况都 很可能会需要较多 的时间进行, 导致页面 UI 出现一段时间不能响应用户操作, 甚至在较低配置的移动设备上 会发生崩溃,这时 Web Workers 便是很好的工具了。 下面列出例子中主要的代码。 index.html 部分 HTML 代码片段 Html 代码 1. <div id="wrap"> 2. <p id="tips"> 3. 输入两个数并计算它们的最大公约数和最小公倍数: 4. <output id="result"></output> 5. </p> 6. <p class="input-data">整数 1: <input id="first"></input></p> 7. <p class="input-data">整数 2: <input id="second"></input></p> 8. <button id="start-worker" onclick="startWorker()">开始 Worker</button> 9. 10. <div id="footer"> 11. <p>Demo by <a href="" target="_blank">Kayo</a></p> 12. </div> 13. </div> JavaScript 代码 Js 代码 1. // 获取用户输入然后发送到 workers 并在后台进行计算 2. function startWorker(){ 3. if(typeof(Worker)!=="undefined"){ 4. 5. var first = document.getElementById('first').value; 6. var second = document.getElementById('second').value; 7. var nums = {'first': first, 'second': second}; 8. 9. // 创建 workers 对象 10. var w = new Worker('demo_workers.js'); 11. w.postMessage(nums); 12. 13. // 接受 workers 从后台返回的数据 14. w.onmessage = function (event){
102
15. 16. 17.
document.getElementById('result').value = event.data; }; } else {
18. alert('抱歉,你的浏览器不支持 Web Workers!'); 19. } 20. };
demo_worker.js 代码 Js 代码 1. // 接收前台的数据并进行计算 2. onmessage = function (event){ 3. var first = event.data.first; 4. var second = event.data.second; 5. var common_divisor = divisor(first, second); 6. var common_multiple = multiple(first, second); 7. // 发送计算结果到前台 8. postMessage("计算完毕! " + "最大公约数为 "+ common_divisor 9. +" 以及最小公倍数为 " + common_multiple); 10. }; 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. // 计算最大公约数 function divisor(a, b) { if (a % b == 0) { return b; } else { return divisor(b, a % b); } }; // 计算最小公倍数 function multiple(a, b){ var multiple = 0; multiple = a * b / divisor(a, b); return multiple; };
103
十七、
HTML5 对 Web App 的影响
在本系列文章的开头,Kayo 曾经介绍过 Web App 的优缺点,并且说明了 HTML5 在其中起 的作用,当然,Web Apps 的发展需要 HTML5 , CSS 与 JavaScript 以及后台技术的共同配 合,但 HTML5 无疑为 Web Apps 发展中一些重要的方面带来主要贡献。本文要阐述的,正 是 HTML5 为 Web Apps 带来的各种影响,或者说,HTML5 究竟为 Web Apps 开发带来了什 么改变。
1. jQuery Mobile 与 HTML5
在具体说明 HTML5 如何使 Web Apps 开发发生改变前,首先回到本系列文章的另一个中心 —— jQuery Mobile 。其实不难想象,倘若没有 jQuery Mobile 等其他移动开发框架,使 用 HTML5 开发 Web Apps 实际上是一件非常困难的事,如果没有 jQuery Mobile ,开发者 就必须在开发过程中独自解决至少以下几个问题:
? ?
创建一个设备检测方案 设计出适应不同移动设备的响应式方案
上面仅仅是一个开始,如果开发者希望能创建一个出色的 Web Apps ,那么还可能需要考虑 以下问题:
? ? ?
设计一套适应移动设备用户使用的 UI 模拟原生 Apps 的各种效果(过场动画等) 模拟原生 Apps 的各种操作(划动等)
更加麻烦的是,即使开发者完成了上面的各项要求,也必须独自调试,确保这些效果能在大 多数移动设备上正确运行, 尤其是需要长期开发时, 开发者需要考 虑的事情就更加复杂了。 因此,jQuery Mobile 等移动开发框架在开发中实际是完成了大部分 CSS 和 JavaScript 的工作,包括开发的工作和在 Web Apps 制作中更为繁琐的调试工作,而 CSS 和 JavaScript 的开发往往也是移动开发中最费时的工作,这也是开发者可以利用 jQuery Mobile 进行快速开发的原因。 也是因为以上的原因, 这篇系列文章才会是“使用 jQuery Mobile 与 HTML5 开发 Web App”,而不是 HTML5 的独唱戏。当然,如果你需要一个完全个性化的样式,开发出自己的 框架或核心主题也无妨。但对于小型的开发者,或者即使你有足够团队支持,但想要进行快 速开 发,使用 jQuery Mobile 等移动开发框架也会更加方便。 当然,实际上 jQuery Mobile 也是一个 HTML5 框架,在 jQuery Mobile 之中也应用 了 HTML5 的新技术,下面开始回归本文的主题 —— HTML5 对 Web Apps 的影响。
2. 你的编程方式
HTML5 确实为 Web 开发者带来了很多很酷的新特性, 但如果你熟悉 HTML5 的新特性, 会发 现大多数 HTML5 的新特性都是使用 JavaScript 进行操作,即使再加上那些不是用
104
JavaScript 操作的特性,使用 HTML5 开发仍然没有改变 Web 前端开发者的编程方式—— 依旧还是使用标签包裹内容,依旧还是使用 CSS 设计样式,依旧还是使用 JavaScript 操 作元素和进行交互。这是一件很好的事,开发者无须为 HTML5 开发付出重新适应编程方式 的代价,因此,你只需在旧技术中拓展学习新的技术,而并不需要推倒重来。
3. HTML5 为 Web Apps 带来的提升
从技术层面上说,几乎每一项 HTML5 新特性都有种为 Web Apps 而设计的意味,W3C 更明 确了某些 HTML5 特性是为 Web Apps 而设的,如 W3C 文档中 "Offline Web applications" 部分正文第一段开头便是: “In order to enable users to continue interacting with Web applications and documents even when their network connection is unavailable” 当然,在这些新特性中有些特性会格外的惊艳,让开发者为之兴奋,除了在系列文章中介绍 到的离线缓存,Offline Web applications ,Web Workers 外,Geolocation ,canvas , Audio 和 Video 等特性都让 Web Apps 发生巨大的进步。下面 Kayo 再进一步说明一下几 个主要特性为 Web Apps 带来的进步。 关于离线缓存,Offline Web applications ,Web Workers 的详细介绍,请参考以下三篇 文章: 《使用 jQuery Mobile 与 HTML5 开发 Web App —— HTML5 Web Storage》 《使用 jQuery Mobile 与 HTML5 开发 Web App —— HTML5 离线缓存》 《使用 jQuery Mobile 与 HTML5 开发 Web App —— HTML5 Web Workers》
1)
离线缓存
与很多原生 Apps 不同,Web Apps 需要通过联网加载元素,这是 Web Apps 中一个致命的 缺点,如果没有网络,Web Apps 将会完全失效。但 HTML5 的离线缓存 (Offline Web applications) 却改变了这一点,离线缓存可以方便地将 HTML 文档 , CSS , JavaScript 以及图片缓存到本地端,并且在缓存成功后优先加载本地端资源,这样导致了 Web Apps 的 性能可以出现两种重要提升: 依赖网络的 Web Apps(网络应用)可以通过离线缓存把占用带宽较高的资源缓存到本地, 大大加快载入速度。同时利用缓存做出脱机时的响应状态。 不依赖网络的 Web Apps(本地应用,单机游戏)可以在有网络连接时把整个程序缓存到本 地,以后无须网络也可以正常使用。
105
2)
Web Workers
Web Workers 可以在后台运行 JavaScript ,这意味着网页在执行 JavaScript 时可以不用 锁定页面的 UI ,因此,可以把进行复杂运算的处理交给 Web Workers 并在后台运行,这 样可以提升 UI 的友好度, 并且减少浏览器 (或标签) 假死的情况。 这样无论是对于 Web Apps 还是普通网页都是一种很好的改进,尤其是对于以应用为主的 Web Apps 。这类 Apps 用户 操作较多,对 UI 的响应能力要求也更高,并且运行在相对于 PC 配置较低的移动设备上, 使用 Web Workers 可以大大提升其性能。另外,Web Workers 可以实现多线程处理,解决 了 JavaScript 单线程运行的问题,Apps 的执行效率也能因此提高。
3)
Web Storage
Web Storage 可以把一些数据存储到本地,与 cookie 相似,但数据是完全存储在本地,并 且数据量大很多, 可以用于存储用户的数据或应用设置, 这样可以方便的读取这些数据而不 占用网络,对于 Web Apps 开发来说也很实用。 以上这几个 HTML5 特性实质上都为 Web Apps 开发作出了同一类贡献——使到 Web Apps 相对原生 Apps 的劣势得以挽回(性能较低和依赖网络的劣势)。也许你会觉得这些特性没 有 jQuery Mobile 为 Web Apps 带来的好处那么直观,但它确实从性能上提升了 Web Apps。 你可以想象,离线缓存可以把大图片缓存到本地,Web Workers 使到用户操作页面时 UI 可 以不用被锁定, 这些特性带来的体验提升远胜于改进一个按钮的样式, 改进一个栏目的布局。 的确,比起外观,性能才从根本上决定了最终的用户体验。 如上面所述,Geolocation ,canvas ,Audio 和 Video 也为 Web Apps 开发带来很多实用 的价值, 但相对于前面 3 点特性在性能方面改进了 Web Apps , 这几点新特性则可以丰富 Web Apps 的内容形式。 另外, 我们再回到 jQuery Mobile , jQuery Mobile 实在也是依赖 HTML5 建立起来,其中 HTML5 的 data- 属性则起到了至关重要的作用,jQuery Mobile 利用 data- 这个 HTML5 中新增加的自定义属性为框架建立了各种组件和功能, 综上所述, HTML5 为 Web Apps 带来的改进主要是以下三个方面:
? ? ?
使到 Web Apps 相对原生 Apps 的劣势得以挽回,这里主要是性能较低和依赖网络 的劣势 提供了更加丰富的内容表现形式 提高开发效率
只有这些好处了? 对,也就只有这些了,与 HTML4 很不相同,HTML5 更像是一个移动开发平台,但也只是一 个平台,关键的开发还是需要开发者的努力。
特别需要指出的是,在本文系列文章开头时,Kayo 还介绍了另一种 HTML5 的新特性—— Web SQL Database ,从实用性来上说,Web SQL Database 允许开发者在本地使用 SQL 数
106
据库(SQLite),这是个很实用的功能,但很遗憾,由于 SQL 本身并不是一套统一的标准, 因此 W3C 认为 Web SQL Database 也不能成为标准,并在 10 年的 W3C TPAC 中把 Web SQL Database 从“工作草案”的状态变更为“工作小组报告”,这意味 Web SQL Database 也 不将被 W3C 推荐(不再更新),而以 Indexed Database 取而代之。
4. 需要渐进增强的设计
如果你已经阅读了上面列出的三篇文章,会发现 HTML5 在不同的平台和浏览器中的兼容性 并不算是十分出色,即使你的 App 只需支持一、两个平台,但 HTML5 的某些特性在这些平 台中仍有可能表现出较大的差异。因此,如果开发者使用 HTML5 进行 Web Apps 开发,那 么就需要进行渐进增强的设计。 关于渐进式设计, 这里再一次引用 Kayo 在之前的文章中写 过的一段关于渐进增强设计的描述: “前端设计时通过渐进增强功能来设计一直也是 Kayo 的设计想法, 因为不同的平台, 不同 的设备有着不同的 Web 环境,因此对于一些出色的前端效果很难保证在每台设备上都呈现 相同的效果, 因此与其为了在所有设备上做到一样的效果而降低整体的前端样式, 不如对于 好的设 备可以呈现更出色的效果,而基本的效果就兼容所有的设备。jQuery Mobile 的设 计也是如此, 核心的功能支持所有的设备, 而较新的设备则可以获得更为优秀的页面效果。 ”
如上面所述,jQuery Mobile 也是渐进增强设计的,事实上每个主流的移动开发框架都是基 于渐进增强设计的, 但开发者使用 HTML5 开发时仍需考虑 HTML5 方面的渐进增强设计, 简 而言之,开发者应该为 HTML5 新特性设计好一个备用解决方案。
这里 Kayo 必须指出一点, 渐进增强设计是必须从项目一开始就需要进行规划的设计, 它意 味着一个样式或功能需要同时考虑多种技术的支持情况,即考虑渐进增强设计必须从 底层 考虑, 包括 Web Apps 功能上的设计, 样式上的设计, 目标用户群使用的主流平台和浏览器, 这些开发者都必须从一开始就考虑清楚,决定 Web Apps 中哪些样式或功能需要考虑渐进增 强,具体的解决办法又如何。
举一个简单的例子,使用 Web Storage 的 localStorage 存储一些用户信息,不支持 localStorage 的浏览器使用 cookie 代替,这时开发者必须考虑两个问题——存储哪些信 息?信息的大小和格式?localStorage 是直接保存在本地端的,cookie 则一般由 CGI 处 理程序加密后再发送到本地, 因此同时考虑两种技术的支持情况, 密码这类重要的信息最好 还是不要存储;localStorage 键值只支持字符串,cookie 的键值形式则可以更加丰富,因 此同时考虑两种技术, 这些信息最好是字符串的形式, 或是由其他形式转为字符串形式后再 保存。这样,两种技术才能在 Web Apps 开发中互相代替,最终的效果是使到设备在不支持 更好的技术时可以优雅的降级到其他技术。
5. 解决方案与实例
107
现在,读者大概已经了解到使用 HTML5 开发一个 Web Apps 的各种影响了,HTML5 的新特 性并没有改变你的编程方式,但却改变了你的开发过程。因此,即使开发者已经很熟悉网站 开发,但如果需要长期开发 Web Apps ,仍要针对以上各项设计一个前端解决方案。当然, 具体的解决方案可以有很多,这里 Kayo 以 jQuery Mobile 与 HTML5 开发为例,说明一个 快速开发的解决方案。
在说明解决方案之前, Kayo 首先介绍一下例子 Demo 的情况, 例子是一个记事本功能的 Web Apps ,与本系列开头介绍过的例子记事本不一样,本例子中的事件输入会稍复杂一些,并 且以 Mysql 数据库代替 Web SQL Database ,后台使用 PHP 。
接下来,Kayo 介绍一下使用 jQuery Mobile 与 HTML5 快速开发 Web Apps 的一个解决方 案:设备检测方案、响应式设计、UI、模拟原生 Apps 的各种效果和操作主要交给 jQuery Mobile 框架,选项存储使用 Web Storage ,并使用 manifest 存储静态的文件(CSS、 JavaScript、图片),由于内容是动态生成的,因此页面文档没有使用 manifest 缓存,实 际上,若开发者使用主流的移动开发框架进行 Web Apps 快速开发,都可以尝试使用这个方 案,基本上这个方案已经可以调节好开发的需要与效率的问题。 现在,可以打开下面的例子,感受 HTML5 开发 Web Apps 的魅力了!
108
更多相关文档:
推荐jQuery Mobile插件和教程
推荐jQuery Mobile插件和教程_计算机软件及应用_IT/计算机_专业资料。jQuery Mobile 是 jQuery 在手机上和平板设备上的版本。jQuery Mobile 不仅会给主流移动平台带来...
DW基础使用教程
DW基础使用教程_计算机软件及应用_IT/计算机_专业资料。DW基础使用教程,内容较...jQuery Mobile 不仅会给主流 移动平台带来 jQuery 核心库,而且会发布一个完整...
JQueryMobile视频教程-JQueryMobile从入门到精通配项目...
JQueryMobile视频教程-JQueryMobile从入门到精通配项目实战_计算机软件及应用_IT/计算机_专业资料。JQueryMobile视频教程项目讲解部分:jquery实例教程第13章:项目一:日程...
jQuery_Mobile入门教程_提升篇
在之前的文章 jQuery Mobile 入门教程里,我对 jQueryMobile 的使用进行了入门介绍, 你可以使用它创造出非常华丽的移动站点——漂亮的按钮、优雅的界面等等等等。 ...
jQuery Mobile入门教程推荐_按钮精解
jQuery Mobile入门教程推荐_按钮精解_计算机软件及应用_IT/计算机_专业资料。jQuery Mobile入门教程推荐_按钮精解jQuery Mobile 入门教程推荐_按钮精解作者原标题:手机网...
jqueryMoblie教程
? jQuery Mobile 图标 jQuery Mobile 事件 jQuery Mobile 教程 jQuery 图标如需在 jQuery Mobile 中向按钮添加图标,请使用 data-icon 属性: Refresh Page 提示:您...
jQuery Mobile使用指南
jQuery_Mobile_教程集合 227页 1下载券 jQuery Mobile知识汇总 147页 免费 jQuery Mobile系列 82页 免费 jQuery Mobile - 9Feb20... 167页 免费 开发者必读jQue...
JQuery Mobile技术文档
JQuery Mobile 权威指南《jQuery Mobile 权威指南》 由资深专家根据 jQuery Mobile 最新版本撰写, 是一本全面 而系统的 jQuery Mobile 教程,对 jQuery Mobile 的...
编程开发---珍藏版资料下载地址
JqueryMobile SenchaTouch 跨平台移动软件开发视频教程(html5 教程,html5 移动...《PHP 网络编程典型模块与实例精讲》扫描版[PDF] 154.1MB 《PHP5 完全攻略》...
51CTO学院-jQuery Mobile入门视频课程(附示例代码)
51CTO 学院 网址:edu.51CTO.com 51cto 学院-jQuery Mobile 入门视频课程(附示例代码)课程目标 jQuery Mobile 是 jQuery 在手机上和平板设备上的版本。jQuery ...
更多相关标签:
jquery mobile 教程 | jquerymobile实例教程 | jquerymobile视频教程 | jquery mobile 精简版 | jquery mobile | jquery mobile demo | jquery mobile 下载 | jquerymobile实例网站 |