现在市场上的大多数移动电话都有功能完善的 Web 浏览器,它们几乎与桌面浏览器没有什么差别。这些移动 Web 浏览器可处理大多数最新的 Web 技术,比如 HTML5、CSS3、JavaScript、DOM 操作和 Ajax。
Dojo Toolkit 已针对桌面 Web 应用程序开发进行了改进,而且 Dojo 可在移动 Web 浏览器上运行。既然 Dojo 已提供了许多有用的小部件,那么我们确实需要针对移动应用程序开发一些小部件吗?是的,有必要,原因如下:
- 输入设备的差异:大多数移动设备都没有鼠标或物理键盘。相反,它们提供了支持手指操作的触摸屏。桌面应用程序上的用户交互包括拖放应用程序、鼠标悬停操作、键盘快捷键和导航(使用 TAB 键或方向键导航)等,它们对移动设备提出了挑战。移动设备的任何 UI 小部件都应该支持触摸。
- 更小的屏幕:移动界面很小,用户在触摸屏上使用手指。恰当地设计移动设备的 UI 很重要。此外,平板设备的屏幕大小比智能手机的屏幕要大很多。移动 Web 应用程序需要根据屏幕大小或屏幕方向变换的用户界面。
- 性能问题:尽管移动设备的处理器能力在迅速增加,但是它们的计算能力仍然比台式机的弱。此外,移动网络带宽比台式机的带宽要低得多;有时带宽非常低。移动 Web 应用程序应该占用极小的内存并且性能很高。
Dojo Mobile 是一个基于 Dojo 的小部件集合,用于创建移动 Web 应用程序。它作为 dojox.mobile 引入到了 Dojo 1.5 中,用于解决上述问题。但是,输入设备和屏幕大小问题可使用传统方法解决,即通过添加移动支持来改进现有 Dojo 小部件,无需针对移动设备重新开发小部件。但是,很明显,性能问题无法使用这种方式解决。因此,Dojo Mobile 最重要(和具有挑战性)的一个任务是处理性能问题,尤其是最大程度地减少代码。
Dojo Mobile 的一个有趣功能是,它没有使用任何图像来构建 UI 小部件。基于 WebKit 的浏览器(移动设备上最流行的浏览器)支持 CSS3。CSS3 功能,比如渐变背景、圆角框和 DOM 元素的转换,可在无需使用图像的情况下处理图形表示形式。图 1 显示了 Dojo Mobile 提供的一些 UI 小部件。这些小部件没有使用图像;相反,它们使用了 DOM 元素,比如 <div> 使用 CSS 样式构建其 UI。使用许多图像会增加总下载大小和服务器的 HTTP 请求数量,从而导致性能下降。Dojo Mobile 通过使用 CSS3 功能尽可能避免了此问题。
图 1. 无图像的 Dojo Mobile 小部件
另一方面,用户应用程序可使用图像。图 2 显示了作为 Dojo Mobile 测试文件提供的示例。如您所见,标签栏按钮、列表项图标和图标容器都是图像。滥用图像可导致性能下降,但这是应用程序自己的选择。Dojo Mobile 本身不使用图像,也不会强制用户应用程序使用图像。此外,如您将在后面看到的那样,Dojo Mobile 提供一些有用机制,比如 DOM button 和 CSS sprite,这可以降低图像需求并减少服务器的 HTTP 请求的数量。
图 2. 用户应用程序的图像
当使用图像是不可避免的事情时,有两种可能的方法可以最大程度地减少性能下降。一种方法是通过减少颜色数或增加压缩率来降低图像文件的大小。另一种方法是通过将多个小图像聚合到一个大图像中来减少图像的 HTTP 请求数量。可使用 CSS 属性裁剪和调整组合的大图像,以便它可以用作一个小图像。此技术称为 CSS Sprite,Dojo Mobile 支持这种方法。
清单 1 显示了列表项示例,每个列表项都使用单独的图标。图 3 显示了结果。此示例生成了图像的三个 HTTP 请求。
清单 1. 具有单独图像的列表项
<ul dojoType="dojox.mobile.RoundRectList"> <li dojoType="dojox.mobile.ListItem" icon="i-icon-1.png" moveTo="bar">General</li> <li dojoType="dojox.mobile.ListItem" icon="i-icon-2.png" moveTo="bar">Photos</li> <li dojoType="dojox.mobile.ListItem" icon="i-icon-3.png" moveTo="bar">Store</li> </ul> |
图 3. 清单 1 的结果
另一方面,清单 2 显示了一个使用聚合图像 (i-icon-all.png) 的示例,这由列表项共享。通过指定 ListItem 小部件的 iconPos 属性的逗号分隔值(top、left、width 和 height),您可以重用聚合图像的任意矩形区域。如图 4 所示,结果是一样的,但它仅为聚合图像生成了一个 HTTP 请求。
清单 2. 具有聚合图像的列表项
<ul dojoType="dojox.mobile.RoundRectList" iconBase="i-icon-all.png"> <li dojoType="dojox.mobile.ListItem" iconPos="0,0,29,29" moveTo="bar">General</li> <li dojoType="dojox.mobile.ListItem" iconPos="0,29,29,29" moveTo="bar">Photos</li> <li dojoType="dojox.mobile.ListItem" iconPos="0,58,29,29" moveTo="bar">Store</li> </ul> |
图 4. 清单 2 的结果
CSS Sprite 还可用于图标容器的图标(参见 图 5)或标签栏的按钮(参见 图 6)。
图 5. 使用 CSS Sprite 的 IconContainer
图 6. 使用 CSS Sprite 的 TabBar
Dojo Mobile 为列表项提供简单的按钮、图标和复选标记/箭头等,如图 7 所示。它们通过将没有图像的 CSS 样式应用于 <div> 元素而获得,称为 DOM Button。
图 7. DOM Button
理想情况下,DOM Button 的字节较小,因为它们来自不带图像的 CSS。表 1 比较了 DOM Button 和使用 DomButtonGreenCircleArrow (图 7 中的第四行第一列)作为示例的图像的字节大小。您可以看到 DOM Button 比图像小很多。
表 1. DOM Button 和图像的字节大小比较
| 文件 | 字节大小 |
|---|---|
| DomButtonGreenCircleArrow.css (minified & gzipped) | 392 字节 |
| mblDomButtonGreenCircleArrow.png | 1,599 字节 |
DOM Button 还有其他好处,即不需要进行其他 HTTP 请求,因为可以使用构建工具将它们集成到主题 CSS 文件中。在这种情况下,DOM Button 占用的内存要小很多。表 2 显示了一个聚合 CSS 文件中 DOM Button 的字节大小。您可以看到添加 DomButtonGreenCircleArrow.css 仅增加了 155 个字节。
表 2. 聚合 CSS 文件中 DOM Button 的字节大小
| 文件 | 字节大小 |
|---|---|
| base.css (minified & gzipped) | 2,844 字节 |
| base.css + DomButtonGreenCircleArrow.css (minified & gzipped) | 2,999 字节 |
| Difference | 155 字节 |
DOM Button 由应用了 CSS 样式的多个嵌套的 <div> 元素组成。如前所述,您可以通过使用 CSS3 的丰富功能来实现各种图形表示,比如渐变背景、圆角框和 DOM 元素的转换。您甚至可以通过调整正方形 <div> 元素的边界半径来绘制圆形。图 8 显示了一个 DOM Button 结构的示例。
图 8. DOM Button 的结构
DOM Button 只是一个 CSS 样式集。它不需要 JavaScript 代码。只需放置几个嵌套的 <div> 元素并为它们应用 CSS 样式,就可以显示它们。清单 3 显示了最小示例代码,图 9 显示了结果。
清单 3. 在不使用 JavaScript 的情况下使用 DOM Button
<html>
<head>
<link href="themes/common/domButtons/DomButtonBlueCircleMinus.css" rel="stylesheet">
</head>
<body>
<div class="mblDomButtonBlueCircleMinus">
<div><div><div></div></div></div>
</div>
</body>
</html>
|
图 9. 清单 3 的结果
在 清单 3 中,我准备了 4 个级别的嵌套式 DIV,其中包括 DOM Button 的 root 节点,此 root 节点是一个类名称。但是,所需准备的 DIV 的数量具体取决于 DOM Button 的类型。要自动创建必要数量的 DIV,请使用 Dojo Mobile 的 dojox.mobile.createDomButton() 功能,如 清单 4 所示。
清单 4. 在使用 JavaScript 的情况下使用 DOM Button
<div id="btn1" class="mblDomButtonBlueCircleMinus"></div>
----
var node = dojo.byId("btn1");
dojox.mobile.createDomButton(node);
|
但是,通常不使用 清单 3 和 清单 4。我之所以提供它们是为了展示 DOM Button 的工作原理。相反,一些 Dojo Mobile 小部件支持如下所示的 DOM Button。您可以在图像图标或按钮的位置指定 DOM Button。
- ListItem:icon、rightIcon、rightIcon2、arrowClass 和 checkClass 属性(参见 图 10)
- TabBarButton:icon1 和 icon2 属性(参见 图 11)
- ToolBarButton:icon 属性(参见 图 12)
图 10. ListItem(列表)
图 11. TabBarButton(标签栏)
图 12. ToolBarButton(标题)
您可以创建自己的自定义 DOM Button。下面是一些提示。
- DOM Button 的类名称必须以
"mblDomButton" 开始。Dojo Mobile 检查它来确定按钮是否为 DOM Button 。(另一方面,CSS 文件名和放置位置由您决定。) - 指定 DOM Button 到其根节点的高度和宽度。它们将是整个 DOM Button 的大小。
- <div> 元素是嵌套的,不是同级的。因此,您可能需要对 父节点下的节点应用 CSS 样式。
- 要为 <div> 层次结构中的具体 <div> 元素应用 CSS 样式,可以使用子选择符 (>)。
- 如果您想要支持非 CSS3 桌面浏览器,则应该创建一个等效图像和一个
compat css文件 (*-compat.css)。
清单 5 和 清单 6 显示了一个自定义 DOM Button 示例。图 13 显示了结果。
清单 5. 自定义 DOM Button (DomButtonMyCheck.css)
/* === Red Check Button ==*/
.mblDomButtonMyCheck {
position: relative;
width: 29px;
height: 29px;
}
.mblDomButtonMyCheck > div {
position: absolute;
left: 0px;
top: 8px;
width: 16px;
height: 6px;
font-size: 1px;
-webkit-transform: scaleX(0.7) rotate(135deg);
border-width: 3px 4px 0px 0px;
border-style: solid;
border-color: red;
}
|
清单 6. 自定义 DOM Button (DomButtonMyCheck-compat.css)
/* === Red Check Button ==*/
.mblDomButtonMyCheck {
background-image: url(compat/mblDomButtonMyCheck.png);
background-repeat: no-repeat;
}
.mblDomButtonMyCheck > div {
display: none;
}
|
图 13. 自定义 DOM Button
Dojo Mobile 针对基于 WebKit 的移动浏览器进行了优化,但它也支持非 WebKit 桌面浏览器。但是,没有人希望牺牲移动设备上的性能来支持桌面浏览器。当应用程序在移动设备上运行时,不应加载跨浏览器支持代码。
一种方法是条件编译,这种方法支持您删除移动设备不需要的一些代码块。Dojo 提供了两种条件编译方法 pragmas 和 has()。
Pragmas 是可用于包含/排除一些代码部分的特殊指令,如 清单 7 所示。
清单 7. pragma 使用示例
process: function(){
//>>excludeStart("marker1", kwArgs.noIE);
if(dojo.isIE){
....
}
//>>excludeEnd("marker1");
....
}
|
在上述示例中,如果您使用如下所示的 noIE=true 条件选项构建代码,则会从构建中删除 excludeStart 和 excludeEnd 之间的代码块。
> build profile=myapp action=release noIE=true |
此外,如果您使用 includeStart/includeEnd pragmas,则只有在条件匹配时才会包含包围的代码块。
has()(或者 dojo/has 或 has.js)是一个功能检测/测试机制,包含在 Dojo 1.7 中。如清单 8 所示,您可以使用它来测试当前的运行时环境中是否存在某个特定功能。
清单 8. "has" 测试的示例
process: function(){
if(has("ie")){
....
}
....
}
|
如果您在构建版本中配置 staticHasFeatures 数组,如下所示,会使用 0 代替 has("ie"),然后编译器的优化器将其代码块视为无用代码,并从构建中删除该代码块。
staticHasFeatures: {
'ie': 0
}
|
条件编译支持您针对具体平台进行优化的构建。但是,该构建的问题是它不能在其他平台上工作。要支持其他平台,您需要进行其他构建。要解决此问题,Dojo Mobile 采用了一种不同的方法:兼容性模块(或 compat)。
Compat 包含一些支持非 Webkit 浏览器的代码。如果加载了 compat,它会 "重写" 一些需要修正的小部件方法。
重写代码会保持原始小部件的类名称,不会影响用户的应用程序代码。另一方面,通过将原始小部件划分为多个子类来重写代码将要求新定义的小部件使用新类名称。 Compat 还会加载 *-compat.css 文件,这些文件是原始 css 文件的补丁。在 compat 模式下,传统方法用于在不使用 CSS3 的情况下呈现小部件 UI,比如使用 dojo.fx 的基于 JavaScript 的动画和背景图像等。要为您的应用程序使用 compat,请使用 dojo.require() 或 require API 加载 "dojox.mobile.compat"。
注意,compat 被划分为两部分:compat.js 和 _compat.js。 _compat.js 包含所有实现代码,而 compat.js 是 _compat.js 的加载程序。compat.js 只在当前浏览器是基于 Webkit 的浏览器时才会加载 _compat.js。compat.js 只是一个小代码块,即使它在构建中也不会影响移动性能。这样,在基于 Webkit 的浏览器上,因为永远不会加载 _compat.js ,所以性能不会下降。在非 WebKit 浏览器上,会自动加载 _compat.js,并且 Dojo Mobile 可以在 compat 模式下工作。表 3 显示了具有 compat 的移动版本和没有 compat 的移动版本之间的字节大小比较。如您所见,差别小到可以忽略不计:45 字节。
表 3. 移动版本大小比较(配置文件:mobile-all.profile.js、minified 和 gzipped)
| 描述 | 字节大小 |
|---|---|
| 没有 compat 的移动版本 | 36,594 字节 |
| 具有 compat 的移动版本 | 36,639 字节 |
| 差别 | 45 字节 |
如前所述,在非 WebKit 浏览器上,Dojo Mobile 在 compat 模式下运行,并且会加载其他资源,比如图像和/或 *-compat.css。因此,如果您想要评估在移动设备中加载的文件和文件数量,则应该使用非 WebKit 浏览器,比如 Firefox 或 Internet Explorer。Google Chrome 的调试程序和桌面版 Safari 是监控网络流量的好工具,因为它们都基于 WebKit。
Dojo 提供了很多有用的 API,并且将它们打包为模块,模块是相对小的 JavaScript 文件。有无数的有用模块可用。但是,滥用它们可能会占用大量内存。Dojo Mobile 被精心设计为仅包含少量模块依赖关系。例如,它故意没有使用一些常用的有用模块,比如 dojo.query 或 dijit._Templated。此外,所有 Dojo Mobile 小部件都继承自 dijit._WidgetBase 而不是 dijit._Widget。dijit._WidgetBase 是 dijit._Widget 的基类,不包含移动设备不需要的一些代码,比如键盘支持代码,因此它比 dijit._Widget 更轻。此外,它也不使用 dijit._base.manager,这是 Dojo 1.6 之前的必需模块;相反,它使用 dijit.registry,这是 dijit._base.manager 的子集。
使用像 dojo.query 这样的 dojo 模块还是来自基于 Dojo Mobile 的用户应用程序的 dijit._Templated 当然是您自己的选择。 但是,您应该根据性能慎重地选择使用哪个 dojo/dijit 模块。例如,如果您在应用程序中仅使用了一次 dojo.query,则可使用比整个 dojo.query 实现小很多的代码来代替它。
清单 9 显示了 Dojo Mobile 基类直接或间接相关的模块。您可能注意到,与典型的桌面用例相比,它具有较少的 dojo/dijit 模块依赖关系。它仅与 25 个模块中的 11 个 dojo/_base 模块相关,与 dijit/_base 模块没有任何相关性。如果您使用未在清单 9 中显示的其他模块,则会增加应用程序的内存占用。当您使用此类模块时,应该慎重地选择它们。
清单 9. 依赖关系模块
dijit/_Contained dijit/_Container dijit/_WidgetBase dijit/main dijit/registry dojo/Evented dojo/Stateful dojo/_base/Deferred dojo/_base/array dojo/_base/config dojo/_base/connect dojo/_base/declare dojo/_base/event dojo/_base/kernel dojo/_base/lang dojo/_base/sniff dojo/_base/unload dojo/_base/window dojo/aspect dojo/dom dojo/dom-attr dojo/dom-class dojo/dom-construct dojo/dom-geometry dojo/dom-prop dojo/dom-style dojo/domReady dojo/has dojo/keys dojo/mouse dojo/on dojo/ready dojo/topic |
要优化加载时间性能,构建是一个重要的过程。Dojo 有一个强大的构建系统,会将所有 JavaScript 和 CSS 压缩到较少的文件,并创建一个高效的应用程序版本以供发布。图 15 和图 16 显示了非构建(源代码)应用程序和构建应用程序之间的传输文件比较。您可以看到,它们在请求数量和总体传输大小方面有很大差别。下一部分将讨论构建 Dojo Mobile。
图 14. 请求数量和下载大小(非构建)
图 15. 请求数量和下载大小(构建)
Dojo 构建有一个名为 customBase 的选项。标准 Dojo 构建包含构建中的大多数 Dojo 基础模块,因为 Dojo 基础模块总是可用,所以无需明确要求它们。但是,如果您制作了一个启用了 customBase 选项的构建,则只有实际依赖关系链中的模块包含在构建中。Dojo Mobile 被设计为包含尽量少的 Dojo 基础模块依赖关系。 清单 10 显示了在构建配置文件中如何指定 customBase 选项。
清单 10. 配置文件中的 customBase 选项
dependencies = {
stripConsole: "normal",
layers: [
{
name: "dojo.js",
customBase: true,
dependencies: [
"dojox.mobile.parser",
"dojox.mobile",
"dojox.mobile.compat"
]
},
....
|
可使用两种编译器(或压缩器)生成 Dojo 构建工具,即 Shrinksafe 和 Google Closure Compiler。Shrinksafe 是 Dojo 的默认编译器。从版本 1.7 开始 Closure 就与 Dojo 捆绑在一起。表 4 显示了 Shrinksafe 和 Closure 之间的移动构建大小比较。如您所见,Closure 的压缩率比 Shrinksafe 好,并且 Closure 构建的大小也比 Shrinksafe 构建小 20%,至少在本例中是这样的。
表 4. Shrinksafe 和 Closure 之间的移动构建大小比较
| 描述 | 字节大小 |
|---|---|
| 移动构建 (Shrinksafe, gzipped) | 44,826 字节 |
| 移动构建 (Closure, gzipped) | 36,639 字节 |
Dojo Mobile 已经根据使用 Closure 构建的内容进行了测试。建议对移动构建使用 Closure,因为其输出较小。
Dojo Mobile 提供了两个示例配置文件:mobile-all.profile.js 和 mobile.profile.js,这两个文件都位于 dojo/util/buildscripts/profiles 文件夹。要使用这些文件轻松进行构建,请使用 dojox/mobile/build 文件夹中可用的简单的批处理文件。
从命令行,您可用运行批处理文件。对于 Windows 请使用 build.bat ,对于 Linux 请使用 build.sh。
清单 11. 使用构建批处理文件
> build
Usage: build separate|single [webkit]
separate Create mobile.js that includes only dojox.mobile
single Create a single dojo.js layer that includes dojox.mobile
webkit Enable webkitMobile=true option (Loses PC browser support)
|
separate 使用 mobile.profile.js 并创建仅包含 dojox.mobile 基础模块的 mobile.js。它不包含 dojo 基础模块或 dijit 基础模块。还会为桌面浏览器支持创建 _compat.js。此外,还创建了 dojo.js,但它只是一个普通的 dojo 基础构建,不是 customBase 构建。
注意,"the dojox.mobile base" 不包含所有 Dojo Mobile 小部件。例如,ScrollableView、Carousel、SpinWheel 和表单控件等不包含在此 base 中。如果您想要在构建中使用它们,可将它们添加到配置文件中的依赖关系数组中。清单 12 显示了所有部署到 dojox.mobile 基础构建 mobile.js 中的模块。
清单 12. mobile.js 中的模块
dojox/main dojox/mobile dojox/mobile/EdgeToEdgeCategory dojox/mobile/EdgeToEdgeList dojox/mobile/Heading dojox/mobile/ListItem dojox/mobile/ProgressIndicator dojox/mobile/RoundRect dojox/mobile/RoundRectCategory dojox/mobile/RoundRectList dojox/mobile/Switch dojox/mobile/ToolBarButton dojox/mobile/TransitionEvent dojox/mobile/View dojox/mobile/ViewController dojox/mobile/_ItemBase dojox/mobile/_base dojox/mobile/common dojox/mobile/compat dojox/mobile/sniff dojox/mobile/transition dojox/mobile/uacss |
single 使用 mobile-all.profile.js 并包含一个 dojo.js 层,该层包括 dojox.mobile 基础模块和所有相关 dojo/dijit 模块。还为桌面浏览器支持创建了 _compat.js。此构建支持 customBase 选项。因此,在生成的 dojo.js 中仅包含最少的 dojo/dijit 基础模块。清单 13 显示了部署到单个构建中的所有模块。
清单 13. dojo.js 中的模块
dijit/_Contained dijit/_Container dijit/_WidgetBase dijit/main dijit/registry dojo/Evented dojo/Stateful dojo/_base/Deferred dojo/_base/array dojo/_base/config dojo/_base/connect dojo/_base/declare dojo/_base/event dojo/_base/kernel dojo/_base/lang dojo/_base/sniff dojo/_base/unload dojo/_base/window dojo/aspect dojo/dom dojo/dom-attr dojo/dom-class dojo/dom-construct dojo/dom-geometry dojo/dom-prop dojo/dom-style dojo/domReady dojo/has dojo/keys dojo/mouse dojo/on dojo/ready dojo/topic dojox/main dojox/mobile dojox/mobile/EdgeToEdgeCategory dojox/mobile/EdgeToEdgeList dojox/mobile/Heading dojox/mobile/ListItem dojox/mobile/ProgressIndicator dojox/mobile/RoundRect dojox/mobile/RoundRectCategory dojox/mobile/RoundRectList dojox/mobile/Switch dojox/mobile/ToolBarButton dojox/mobile/TransitionEvent dojox/mobile/View dojox/mobile/ViewController dojox/mobile/_ItemBase dojox/mobile/_base dojox/mobile/common dojox/mobile/compat dojox/mobile/parser dojox/mobile/sniff dojox/mobile/transition dojox/mobile/uacss |
webkit 支持 webkitMobile=true 构建选项,这会将基于 Webkit 的移动浏览器不需要的代码块删除。例如,会从构建中删除特定于 Internet Explorer 或 Firefox 的代码。这会减少总体代码大小,但是构建模块不会在桌面浏览器上工作,即使这些浏览器有兼容性模块 (compat.js)。
还要注意,此选项明显减少了 Dojo 1.6 中的代码量,但在 Dojo 1.7 中,功能检测/测试转移到了 dojo.has,因此 webkitMobile 选项对代码减少不再有明显影响。
Dojo Mobile 在 themes 文件夹下有很多 CSS 文件。每个小部件都有一个 CSS 文件,并且它们可供每个主题(Android、Blackberry、Custom 和 iPhone)使用。此外,还有针对 DOM Buttons 或过渡动画的 CSS 文件。要帮助您轻松地在应用程序中包含必需的 CSS 文件,一些入口点 CSS 文件中汇集了许多相关的 CSS 文件:
- 所有主题文件(示例:themes/iphone/iphone.css)
包含所有常见 CSS 文件和主题 CSS 文件 - 基本主题文件(示例:themes/iphone/base.css)
包含 dojox.mobile 基本模块的主题 CSS 文件 - DOM Buttons (themes/common/domButtons.css)
包含所有 DOM Buttons - 过渡 (themes/common/transitions.css)
包含所有过渡动画
使用所有主题文件是最简单的,因为它包含一切文件。但是,这意味着可能包含无用的 CSS 文件,而这可能会增加不必要的内存占用。在这种情况下,一种方法是使用基本主题文件和未包含在基本主题文件中的单个 CSS 文件。
上述入口点 CSS 文件是 @import 指令的集合。如果您执行 Dojo 构建,会内嵌 @import 语句,并会在入口点 CSS 文件中纳入引用的 CSS 文件。因此,使用一个入口点 CSS 文件仅生成一个 HTTP 请求,如果构建了该文件。但是,如果使用 <link> 或 @import 在应用程序中列出了 CSS 文件,如清单 14 所示,将会为每个文件生成一个 HTTP 请求。
清单 14. html 中的链接标签 (userApp.html)
<head> <link href="../themes/iphone/base.css" rel="stylesheet"> <link href="../themes/iphone/TabBar.css" rel="stylesheet"> <link href="../themes/common/SpinWheel.css" rel="stylesheet"> <link href="../themes/common/domButtons/DomButtonBlueCircleArrow.css" rel="stylesheet"> .... |
要生成所需的请求数量,请使用 @import 指令创建一个入口点 CSS 文件(包含对最少必须 CSS 文件的引用),如清单 15 所示。如果您执行 Dojo 构建,将生成没有外部引用的内联 CSS 文件。您可以从应用程序使用它,如清单 16 所示。
清单 15. 聚合的 CSS 文件 (myStyles.css)
@import url("../themes/iphone/base.css");
@import url("../themes/iphone/TabBar.css");
@import url("../themes/common/SpinWheel.css");
@import url("../themes/common/domButtons/DomButtonBlueCircleArrow.css");
|
清单 16. html 中的一个链接标签 (userApp.html)
<link href="myStyles.css" rel="stylesheet"> |
如前所述,您可以通过创建自己的入口点 CSS 文件并执行 Dojo 构建来减少 CSS 文件的 HTTP 请求数量。
延迟加载(一种只在第一次引用模块时才会加载它们的技术)改进了应用程序的启动性能。Dojo Mobile 本身内部使用的就是延迟加载技术。
使用 _ItemBase 的 url 属性,您可以在进行视图转换之前立刻动态地创建一个新视图。清单 17 显示了一个使用 url 属性的示例。视图内容可以是 HTML 片段(清单 18)或 JSON 数据(清单 19)。
清单 17. url 属性的示例
<ul dojoType="dojox.mobile.RoundRectList">
<li dojoType="dojox.mobile.ListItem" url="view1.html">
External View #1 (sync)
</li>
<li dojoType="dojox.mobile.ListItem" url="view2.json" sync="false">
External View #2 (async)
</li>
</ul>
|
清单 18. 动态视图的 HTML 片段 (view1.html)
<div dojoType="dojox.mobile.View">
<h1 dojoType="dojox.mobile.Heading" back="Home" moveTo="foo">view1.html</h1>
<ul dojoType="dojox.mobile.EdgeToEdgeList">
<li dojoType="dojox.mobile.ListItem">
Jack Coleman
</li>
<li dojoType="dojox.mobile.ListItem">
James Evans
</li>
<li dojoType="dojox.mobile.ListItem">
Jason Griffin
</li>
</ul>
</div>
|
清单 19. 动态视图的 JSON 数据 (view2.json)
{
"dojox.mobile.View": {
"dojox.mobile.Heading": {
"@back": "Home",
"@moveTo": "foo",
"@label": "view1.json"
},
"dojox.mobile.EdgeToEdgeList": {
"dojox.mobile.ListItem": [{
"@label": "Jack Coleman"
}, {
"@label": "James Evans"
}, {
"@label": "Jason Griffin"
}]
}
}
}
|
另一个选项是以编程方式获取视图内容并将它插入目标视图。清单 20 显示了一个示例。
清单 20. 将内容加载到现有视图并进行转换的示例
<li dojoType="dojox.mobile.ListItem" moveTo="#" onclick="myAction2(this)">
Load and Move (async)
</li>
----
function myAction2(li){
var view2 = dijit.byId("view2"); // destination view
var listItem = dijit.byNode(li);
var prog = dojox.mobile.ProgressIndicator.getInstance();
dojo.body().appendChild(prog.domNode);
prog.start();
view2.destroyDescendants();
var url = "http://..."; // or var url = listItem.url;
dojo.xhrGet({
url: url,
handleAs: "text",
load: function(response, ioArgs){
var container = view2.containerNode;
container.innerHTML = response;
dojo.parser.parse(container);
prog.stop();
listItem.transitionTo("view2");
}
});
}
|
请参见 dojox/mobile/tests/test_list-actions.html 了解详细信息和更多示例。
IconContainer 可以拥有多个图标,每个图标都表示一个子应用程序。子应用程序可由一个或多个 Dojo 小部件组成。在启动时加载所有子应用程序代码可能会增加主应用程序的启动时间。要改进启动时间性能,您可以指定 IconItems 上的 lazy="true" 参数。然后,Dojo 解析器会跳过 IconItem 内部的小部件实例化,并且在第一次打开图标时,IconContainer 会动态地加载这些图标内容模块并实例化它们。
清单 21 是一个图标内容的延迟加载示例。注意,您无需明确要求图标内容模块(下列示例中的 dijit.CalendarLite)。还要注意,在 Dojo 1.7 中,只有在同步加载程序的模式下才支持延迟加载,因为使用 dojo.require 可同步执行延迟加载。
清单 21. IconContainer 的延迟加载示例
<ul dojoType="dojox.mobile.IconContainer">
<li dojoType="dojox.mobile.IconItem" label="Calendar" lazy="true">
<div id="cal" dojoType="dijit.CalendarLite"></div>
</li>
....
|
图 16. IconContainer
如果您需要可延迟加载的标签面板,可使用 TabBar 小部件和在 "动态地创建视图" 中介绍的技术。对于标签面板,对第一个标签面板还有一些技巧,因为在启动时没有视图转换。您需要在启动时以编程方式进行从空白视图到第一个标签面板的视图转换,以将外部内容加载到第一个标签面板。清单 22 和清单 23 显示了相同的示例;前一个是同步示例,后一个是异步示例。
清单 22. 延迟标签面板的示例(同步模式)
<script src="../../../dojo/dojo.js" djConfig="parseOnLoad: true"></script>
<script language="JavaScript" type="text/javascript">
dojo.require("dojox.mobile");
dojo.require("dojox.mobile.parser");
dojo.require("dojox.mobile.compat");
dojo.require("dojox.mobile.TabBar");
dojo.ready(function(){
setTimeout(function(){
dijit.byId("tab1").onClick();
}, 0);
});
</script>
</head>
<body style="visibility:hidden;">
<ul dojoType="dojox.mobile.TabBar" barType="segmentedControl">
<li id="tab1" dojoType="dojox.mobile.TabBarButton" url="view1.html">New</li>
<li id="tab2" dojoType="dojox.mobile.TabBarButton" url="view2.html">What's Hot</li>
<li id="tab3" dojoType="dojox.mobile.TabBarButton" url="view3.html">Genius</li>
</ul>
<div id="blank" dojoType="dojox.mobile.View" selected="true"></div>
<div id="view1" dojoType="dojox.mobile.View"></div>
<div id="view2" dojoType="dojox.mobile.View"></div>
<div id="view3" dojoType="dojox.mobile.View"></div>
</body>
|
清单 23. 延迟标签面板的示例(异步模式)
<script src="../../../dojo/dojo.js" djConfig="async: true, parseOnLoad: true"></script>
<script language="JavaScript" type="text/javascript">
require([
"dojo/_base/kernel",
"dijit/registry",
"dojox/mobile",
"dojox/mobile/compat",
"dojox/mobile/parser",
"dojox/mobile/TabBar"
], function(dojo, registry){
dojo.ready(function(){
setTimeout(function(){
registry.byId("tab1").onClick();
}, 0);
});
});
</script>
</head>
<body style="visibility:hidden;">
<ul dojoType="dojox.mobile.TabBar" barType="segmentedControl">
<li id="tab1" dojoType="dojox.mobile.TabBarButton"
url="view1.html" sync="false">New</li>
<li id="tab2" dojoType="dojox.mobile.TabBarButton"
url="view2.html" sync="false">What's Hot</li>
<li id="tab3" dojoType="dojox.mobile.TabBarButton"
url="view3.html" sync="false">Genius</li>
</ul>
<div id="blank" dojoType="dojox.mobile.View" selected="true"></div>
<div id="view1" dojoType="dojox.mobile.View"></div>
<div id="view2" dojoType="dojox.mobile.View"></div>
<div id="view3" dojoType="dojox.mobile.View"></div>
</body>
|
在运行时动态地要求模块是个好主意,因为这可以改进启动时间性能。但是要注意一个潜在问题。看看清单 24,它显示了以编程方式加载 Dojo 模块。它可以工作,但是如果您构建清单 24,构建工具将自动选择所需模块,并将它部署到构建中,因此在运行时 dojo.require 不执行任何操作,因为已在启动时加载了该模块。
清单 24. 以编程方式加载 Dojo 模块(错误示例)
myHandler: function(e){
dojo.require("dijit.CalendarLite");
var cal = new dijit.CalendarLite();
....
}
|
要避免这种问题,您可以编写 dojo["require"] 而不是 dojo.require,如清单 25 所示。
清单 25. 以编程方式加载 Dojo 模块(正确示例)
myHandler: function(e){
dojo["require"]("dijit.CalendarLite");
var cal = new dijit.CalendarLite();
....
}
|
如果正在异步加载您的应用程序,则语法与清单 26 显示的不同。但是,这也不是一个好示例,因为如果以这种方式编写代码,构建工具会意外地选择指定的模块。
清单 26. 以编程方式加载 Dojo 模块(错误示例)
myHandler: function(e){
require(["dijit/CalendarLite"], lang.hitch(this, function(module){
var cal = new module();
....
}));
}
|
可以通过将类名称指定给变量来避免此构建问题,如清单 27 所示。
清单 27. 以编程方式加载 Dojo 模块(正确示例)
myHandler: function(e){
var cls = "dijit/CalendarLite"; // assign to a variable so as not to be in the build
require([cls], lang.hitch(this, function(module){
var cal = new module();
....
}));
}
|
在 Dojo 1.7 中,除了传统的 Dojo 加载器,还提供了新 AMD (Asynchronous Module Definition) 加载器。Dojo Mobile 小部件以新 AMD 语法编写。要加载任意 Dojo 模块,您可以使用传统 dojo.require(清单 28)或新 API(清单 29)。
清单 28. dojo.require 的示例(传统)
<script src="../dojo/dojo.js" djConfig="parseOnLoad: true"></script>
<script language="JavaScript" type="text/javascript">
dojo.require("dojox.mobile");
dojo.require("dojox.mobile.parser");
dojo.require("dojox.mobile.compat");
</script>
|
清单 29. require 的示例(AMD 语法)
<script src="../dojo/dojo.js" djConfig="async:true, parseOnLoad:true"></script>
<script language="JavaScript" type="text/javascript">
require([
"dojox/mobile",
"dojox/mobile/parser",
"dojox/mobile/compat"
]);
</script>
|
清单 28 同步加载了模块,而清单 29 则异步加载模块。在加载了大量 JavaScript 文件的情况下,预计异步加载比同步加载执行得更好。但是,如果将 JavaScript 文件合并到一个构建文件中,则同步加载和异步加载没有太大差别。
但是,您应该注意一个较大的差异。图 18 显示了打开 test_iPhone-Animation.html(以清单 28 所示的方式加载模块)时的传输文件,而图 19 显示了打开 test_iPhone-Animation-async.html(以清单 29 所示的方式加载模块)时的传输文件。如表 5 所示,在同步模式中,会额外加载 17 个文件,总共 26KB。这是因为同步模式以向后兼容性模式进行工作,因此需要加载更多必需模块来保持向后兼容性。假设 test_iPhone-Animation-async.html 在没有这些额外模块的情况下进行工作,显然不会使用并加载它们。因此,即使您慎重地选择了使用的模块,并使用 customBase 选项优化构建,使用 dojo.require() 可能会破坏您的工作。您应该使用 require API 而不是 dojo.require() 来优化应用程序的性能。
图 17. 同步加载 (test_iPhone-Animation.html)
图 18. 异步加载 (test_iPhone-Animation-async.html)
表 5. 同步模式和异步模式之间的资源下载比较
| 文件 | 请求的数量 | 总大小 |
|---|---|---|
| test_iPhone-Animation.html | 23 | 69.15 KB |
| test_iPhone-Animation-async.html | 6 | 43.54 KB |
顺便说一下,即使您使用像清单 29 那样的 AMD 语法,如果您不指定 async:true(默认值是 false),则您的应用程序将在兼容性模式下运行并且会加载其他模块。
dojox.mobile.parser 是 dojo.parser 的一个小子集。设计它纯粹是为了降低总体代码大小。它没有特定于移动的额外功能,除了 dojo.parser,因此没有理由使用 dojox.mobile.parser 代替 dojo.parser。您可以使用自己喜欢的功能。在 dojox.mobile.parser 中删除了 dojo.parser 的一些高级功能,比如 <script type="dojo/method"> 和 <script type="dojo/connect">,因此 dojox.mobile.parser 比较小。
如表 6 所示,dojox.mobile.parser 的大小大约为 0.7KB (minified & gzipped),而 dojo.parser(加上 dojox.mobile 基础模块不需要的其依赖关系模块)为 6.5KB。如果 dojox.mobile.parser 的功能对您的应用程序来说足够了,则使用它可降低应用程序的总体代码大小。
表 6. dojox.mobile.parser 和 dojo.parser 之间的大小比较
| 描述 | 字节大小 |
|---|---|
| dojox.mobile.parser | 734 字节 |
| dojo.parser + 依赖关系模块 | 6,507 字节 |
本文展示了如何使用 Dojo Mobile 构建轻量级移动 Web 应用程序,以及如何将此性能优化技术应用于您的应用程序。
学习
- 了解 Dojo 的 mobile 功能。
- 阅读最新的 dojox.mobile 文档。
- 试用最新的 Dojo Mobile 1.7 每夜构建测试。
- 在developerWorks Web 开发专区中,找到数百篇 how-to 文章和教程,以及为 Web 开发人员准备的下载、讨论论坛和其他丰富资源。
- 在 developerWorks 的 Mobile 开发博客 中查找关于 mobile 的更新。
- 您可以在 developerWorks 上找到更多 关于移动主题的文章,包括 关于 Dojo Mobile 的文章。
- 随时关注 developerWorks 技术加油站,了解各种 IBM 产品和 IT 行业话题。
- 观看 developerWorks 演示中心,包括包括面向初学者的产品安装和设置演示,以及为经验丰富的开发人员提供的高级功能。
获得产品和技术
- 从 Dojo Toolkit 下载页面 下载最新的 Dojo 1.7。
- 下载和试用 IBM Mobile Technology Preview,这是一个代码示例和服务集合,帮助您开始构建扩展和集成到企业中的移动应用程序。预览版包括 RESTful 通知服务、PhoneGap(构建混合移动应用程序的开源框架)、轻量级 WebSphere Application Server 运行时和示例代码,支持您查看它们如何工作。
-
IBM WebSphere Application Server Feature Pack for Web 2.0 and Mobile 包括 IBM Dojo 1.7 Toolkit,这是一种移动的富 Internet 应用程序 (RIA) 构建块和基于 Dojo 的图形组件。使用随附提供的 Rational 工具,Feature Pack 有助于您利用最初针对桌面浏览器开发的 WebSphere 应用程序,然后改编它们并将它们部署到移动设备。
- 以最适合您的方式
评估 IBM 产品:下载产品试用版,在线试用产品,在云环境下试用产品,或者在 SOA Sandbox 中花费几个小时来学习如何高效实现面向服务架构。
讨论
- 加入 developerWorks 社区。查看开发人员推动的博客、论坛、组和 wikis,并与其他 developerWorks 用户交流。
