原文: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的设计草图如下:
中间是Feed视图,用于展示与搜索相匹配的图片列表。顶部有两个按钮,左边的跳转到第一个Setting视图,右边的刷新搜索结果。点击图片列表中任意项,跳转到对应的第三个Details视图。
设置视图可以设置API请求参数:
- tags
- selection
- feed language
发布事件,作者,图片详情都将会在请求返回的JSON结果中,具体情况稍后做详细讲解。
移动开发指南
较多麻袋!在我们为FlickrView编码之前,关于Dojo Mobile与移动web应用开发的一些事情需要交代 :
- 大小问题
当创建移动应用时每一字节都应计算清楚,所有有些捷径在标准应用中可行但在移动应用用不一定可行。记得每个依赖都会zengjia用户的下载时间。
- 最佳实践 mobile!=web
javascript的最佳实践与javascript工具集的最佳实践。一些例子没有包含原生扩展,不使用全局变量,创建灵活而通用的类。追求最佳实践将需要写更多的代码,所以为了创建高效的移动应用需要适当放宽一些规则限制。
- 保持简单
创建一个复杂的应用带有一大堆自定义的样式,挂件与布局,应用会运行的很慢。所有创建简单的布局,然后添加它是有效的优化方案。
我们不会就此抛弃最佳实践,我们会在高效与最佳实践之间寻找一个平衡点。
组织你的项目
应用的HTML文件在项目的根目录,javascript,图片,样式都会有各自的子目录。
我们给HTML文件取名为flickrview.html,然后把样式放在css文件css/flickrview.css中。稍后我们会添加图片与javascript。
移动设备与缓存
很多移动设备对数据传输都有严重的缓存依赖。本身对于线上产品是很多好的,但是对于开发调试则就成了噩梦。在开发设置页面之前,让我们添加一些防止缓存的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结构
在第一部分,Getting Started with Dojo Mobile中提供了一个固定的模版,在开始处包含了样式表与脚本标签。
在我们定义三个视图之前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:
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挂件
- 将会刷新Feed视图的内容
- 切换到Settings视图
- 切换到Feed视图
- 切换回到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。