翻译 - 【Dojo Tutorials】Part 2 - Developing a Dojo Mobile Application: FlickrView

原文:Developing a Dojo Mobile Application: FlickrView

在本系列的第一篇文章Getting Started with Dojo Mobile中,详细的讲述了Dojo工具集中dojox/mobile包的基本概念与使用方法。在接下来的文章中,我们将创建一个功能齐全的Dojo Mobile web应用,叫做FlickrView。本文主要让你熟悉什么是FlickrView,我们想做什么,然后会构建这个应用的HTML与CSS布局。

FlickrView是什么?

FlickrView是我们将要使用Dojo Mobile与我们自定义的一些资源来创建的应用的名字。FlickrView不是Dojo Mobile的一个小练习;FlickrView是一个有用的,功能齐全的移动web应用。关于FlickrView我们的目标如下:

  • 利用Dojo Mobile的挂件创建一个设备兼容的移动应用
  • 添加我们自定义的挂件,控制器和功能到web应用中
  • 使用JSONP连接Flickr的开放API来获取匹配的公开照片

应用的设计与需求

FlickrView的设计草图如下:

settingsfeeddetails

中间是Feed视图,用于展示搜索到的图片列表。顶部有两个按钮,左边的用于跳转到第一个Settings视图,右边的用于刷新搜索结果。点击图片列表中任意项,跳转到对应的第三个Details视图。

Settings视图可以设置API请求参数:

  • tags
  • selection
  • feed language

图片的发布时间,作者和图片详情都将会在请求返回的JSON数据中,具体情况稍后做详细讲解。

移动开发指南

等一等!在我们为FlickrView编码之前,关于Dojo Mobile与移动web应用开发有一些事情需要交代 :

  • 大小问题

  当创建移动应用时每一字节都应计算清楚,所以有些捷径在标准应用中可行但在移动应用用不一定可行。每个依赖都会增加用户的下载时间。

  • 最佳实践 mobile!=web

  javascript的最佳实践与javascript工具集的最佳实践。一些例子没有包含原生扩展,不使用全局变量,创建灵活而通用的类。追求最佳实践将需要写更多的代码,所以为了创建高效的移动应用需要适当放宽一些规则限制。

  • 保持简单

  创建一个复杂的,带有一大堆自定义的样式,挂件与布局的应用时,应用会变得很慢。所以创建简单的布局,然后添加它是有效的优化方案。

我们不会因此抛弃最佳实践,我们会在高效与最佳实践之间寻找一个平衡点。

组织你的项目

应用的HTML文件在项目的根目录,javascript,图片,样式都会放置在各自目录中。

我们给HTML文件取名为flickrview.html,然后把样式放在css文件css/flickrview.css中。稍后我们会添加图片与javascript。

移动设备与缓存

很多移动设备在数据传输时都会使用缓存。本身对于线上产品这是很好的,但是对于开发调试则就成了噩梦。在开发Settings页面之前,让我们添加一些防止缓存的META标签在HTML页面中:

1 <!-- prevent cache -->
2 <meta http-equiv="cache-control" content="no-cache"/>
3 <meta http-equiv="pragma" content="no-cache"/>

这些META标签在开发的时候是很有用的,但是发布的时候记得要删除掉。

FlickrView HTML结构

本系列的第一篇文章中提供了一个固定的模版,在开始处包含了样式表与脚本标签。

在我们定义三个视图之前HTML结构应该是这样的:

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <meta http-equiv="Content-type" content="text/html;charset=utf-8"/>
 5         <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no"/>
 6         <meta name="apple-mobile-web-app-capable" content="yes"/>
 7         <!-- prevent cache -->
 8         <meta http-equiv="cache-control" content="no-cache"/>
 9         <meta http-equiv="pragma" content="no-cache"/>
10 
11         <link rel="stylesheet" type="text/css" href="css/flickrview.css"/>
12         <script type="text/javascript" src="dojox/mobile/deviceTheme.js"></script>
13         <script type="text/javascript">
14             dojoConfig = {
15                 async: true,
16                 baseUrl: '../',
17                 parseOnload: false,
18                 mblHideAddressBar: true,
19                 packages: [{
20                     name: "flickrview",
21                     location: "js"
22                 }]
23             };
24         </script>
25         <script type="text/javascript" src="dojo/dojo.js"></script>
26         <script type="text/javascript">
27             require([
28                 "dojox/mobile/parser",
29                 "dojox/mobile/compat",
30                 "dojo/domReady!"
31             ], function(parser) {
32                 parser.parse();
33             });
34         </script>
35     </head>
36     <body style="visibility:hidden;">
37         application will go here
38     </body>
39 </html>

有了这个模版,把我们的所有视图放置在一起:FeedView,SettingsView和DetailView:

  Details

Feed视图

 1 <!-- Feed View -->
 2 <div id="feed" data-dojo-type="dojox/mobile/ScrollableView" data-dojo-props="selected:true">
 3     <div id="feedHeading" data-dojo-type="dojox/mobile/Heading" data-dojo-props="fixed:'top',label:'Feeds'">
 4         <span data-dojo-type="dojox/mobile/ToolBarButton" data-dojo-props="icon:'../images/image-1.png',moveTo:'settings',transitionDir:'-1',transition:'none'" style="float:left;"></span>
 5         <span id="refreshButton" data-dojo-type="dojox/mobile/ToolBarButton" data-dojo-props="icon:'../images/image-1.png'" style="float:right;"></span>
 6     </div>
 7     <div id="feedList" data-dojo-type="dojox/mobile/EdgeToEdgeList">
 8         <div data-dojo-type="dojox/mobile/ListItem" data-dojo-props="moveTo:'details',transition:'slide'" class="photoListItem">
 9             <img src="../images/photo1.png" width="80px" height="80px" alt="Title" style="float:left;"/>
10             <div class="photoSummary">
11                 <div class="photoTitle">Photo title here</div>
12                 <div class="publishedTime" data-dojo-time="2014-10-10">published date here</div>
13                 <div class="author">author here</div>
14             </div>
15             <div class="summaryClear"></div>
16         </div>
17         <div data-dojo-type="dojox/mobile/ListItem" data-dojo-props="moveTo:'details',transition:'slide'" class="photoListItem">
18             <img src="../images/photo1.png" width="80px" height="80px" alt="Title" style="float:left;"/>
19             <div class="photoSummary">
20                 <div class="photoTitle">Photo title here</div>
21                 <div class="publishedTime" data-dojo-time="2014-10-10">published date here</div>
22                 <div class="author">author here</div>
23             </div>
24             <div class="summaryClear"></div>
25         </div>
26     </div>
27 </div>

Settings视图

 1 <!-- Settings view -->
 2 <div id="settings" data-dojo-type="dojox/mobile/ScrollableView">
 3     <div data-dojo-type="dojox/mobile/Heading" data-dojo-props="fixed:'top',label:'Settings'">
 4         <span id="doneButton" data-dojo-type="dojox/mobile/ToolBarButton" data-dojo-props="label:'Done',moveTo:'feed',transition:'none'" style="float:right;"></span>
 5     </div>
 6     <div data-dojo-type="dojox/mobile/RoundRect">
 7         <div data-dojo-type="dojox/mobile/FormLayout" data-dojo-props="columns:'two'">
 8             <div>
 9                 <label for="tags">Tags</label>
10                 <fieldset>
11                     <input type="text" id="tags" data-dojo-type="dojox/mobile/TextBox" data-dojo-props="value:''"/>
12                 </fieldset>
13             </div>
14             <div>
15                 <label for="select">Selection</label>
16                 <fieldset>
17                     <input type="checkbox" id="select" data-dojo-type="dojox/mobile/Switch" value="on" leftLabel="All" rightLabel="Any"/>
18                 </fieldset>
19             </div>
20             <div>
21                 <label>Feed language</label>
22                 <fieldset>
23                     <input id="en-us" data-dojo-type="dojox/mobile/RadioButton" checked type="radio" name="feedLanguage" value="en-us"/><label for="en-us">English</label><br/>
24                     <input id="fr-fr" data-dojo-type="dojox/mobile/RadioButton" checked type="radio" name="feedLanguage" value="fr-fr"/><label for="fr-fr">French</label><br/>
25                     <input id="de-de" data-dojo-type="dojox/mobile/RadioButton" checked type="radio" name="feedLanguage" value="de-de"/><label for="de-de">German</label><br/>
26                     <input id="it-it" data-dojo-type="dojox/mobile/RadioButton" checked type="radio" name="feedLanguage" value="it-it"/><label for="it-it">Italian</label><br/>
27                     <input id="ko-kr" data-dojo-type="dojox/mobile/RadioButton" checked type="radio" name="feedLanguage" value="ko-kr"/><label for="ko-kr">Korean</label><br/>
28                     <input id="pt-br" data-dojo-type="dojox/mobile/RadioButton" checked type="radio" name="feedLanguage" value="pt-br"/><label for="pt-br">Portuguese</label><br/>
29                     <input id="es-us" data-dojo-type="dojox/mobile/RadioButton" checked type="radio" name="feedLanguage" value="es-us"/><label for="es-us">Spanish</label><br/>
30                     <input id="zh-hk" data-dojo-type="dojox/mobile/RadioButton" checked type="radio" name="feedLanguage" value="zh-hk"/><label for="zh-hk">Traditional Chinese (HK)</label><br/>
31                 </fieldset>
32             </div>
33         </div>
34     </div>
35 </div>

Details视图

1 <!-- Details View -->
2 <div id="details" data-dojo-type="dojox/mobile/ScrollableView">
3     <div id="detailsHeading" data-dojo-type="dojox/mobile/Heading" data-dojo-props="fixed:'top',label:'Details',back:'Back',moveTo:'feed',transition:'slide',transitionDir:'-1'"></div>
4     <div id="detailsContainer" data-dojo-type="dojox/mobile/RoundRect">
5         Photo description from Flickr here
6     </div>
7 </div>
  • 我们使用了dojox/mobile/ScrollableView而不是dojox/mobile/View。ScrollableView允许在内容滚动的时候头部固定不动。它非常适合用于小屏设备或当内容数量不确定的时候。
  • 头部我们使用dojox/mobile/Heading,我们还添加了dojox/mobile/ToolBarButton挂件
    • refresh将会刷新Feed视图的内容
    • settings切换到Settings视图
    • done切换到Feed视图
    • back切换回到Feed视图
  • 注意ToolBarButton的data-dojo-props属性:刷新与设置按钮都是使用图片渲染的,用icon属性声明图片。
  • moveTo定义目标,transition定义切换类型,transitionDir定义切换方向。更多详情请查看dojox/mobile/Heading
  • 在Feed页面我们定义了两个dojox/mobile/ListItem挂件。最终我们会利用JSONP请求的结果生成列表项的。
  • 自定义CSS仅用于列表项。其他的样式在Dojo Mobile主题中都已提供了。

同样不要忘记了把使用到的挂件都引入到HTML中:

 1 require([
 2     // ...
 3     "dojox/mobile/ScrollableView",
 4     "dojox/mobile/Heading",
 5     "dojox/mobile/ToolBarButton",
 6     "dojox/mobile/EdgeToEdgeList",
 7     "dojox/mobile/ListItem",
 8     "dojox/mobile/RoundRect",
 9     "dojox/mobile/FormLayout",
10     "dojox/mobile/TextBox",
11     "dojox/mobile/Switch",
12     "dojox/mobile/RadioButton",
13     "dojo/domReady!"
14 ], function(parser) {
15     parser.parse();
16 });

至此我们应用的布局已经完成了。

FlickrView已经成型!

创建基础框架是很简单的:添加在滚动试图,工具栏挂件。需要指出的是我们应用的各个部分都是包含在dojox/mobile中的:如Headings,ToolBars,TextBox等等,他们都很容实现。

现在我们要对ScrollabelView进行扩展:

  • Settings视图展示当前配置与更新flickrview。按照用户的输入去查询
  • Feed视图用于获取数据并展示结果

扩展ScrollableView

首先通过创建骨架文件js/FeedView.js与js/SettingsView.js来定义我们的类:

1 define([
2     "dojo/_base/declare",
3     "dojox/mobile/ScrollableView"
4 ], function(declare, ScrollableView) {
5     return declare([ScrollableView]);
6 });

现在我们更新HTML属性data-dojo-type使用新的类:

1 <!-- Feed View -->
2 <div id="feed" data-dojo-type="flickrview/FeedView">
3 
4 <!-- Settings view -->
5 <div id="settings" data-dojo-type="flickrview/SettingsView">

与此同时我们需要引入我们的类名以确保解析器载入了它们:

1 require([
2     // ...
3     "flickrview/FeedView",
4     "flickrview/SettingsView"
5 ], function(parser) {
6     // ...
7 });

恭喜!我们的模拟程序为feed与settings视图使用了我们专有的类。

本文介绍了我们使用Dojo Mobile要构建的应用:FlickrView。从应用的设计和要求开始,接着我们构建了布局模版。我们还讲了最佳实践与扩展ScrollableView以满足我们的特殊需要!

下一篇教程中我们将实现FeedView的具体细节:

  • 使用dojo/requrest/script从Flickr获取feeds
  • 构建一个自定义列表

下载源码

Download Part 2 - Developing a Dojo Mobile Application:FlickrView。