英文原链接:
http://dojotoolkit.org/documentation/tutorials/1.9/mobile/flickrview/part3/
上一篇,
开发一个移动应用程序,我们构建了通用布局模板和搭建了一个静态应用。本篇将静态内容更新为从Flickr动态获取数据和展示feeds.你会学到从JSON获取响应内容和处理异常,使用进度表表示在等待服务器的返回,动态填充队列,使用基本HTML模板创建队列和将数据格式化为特定的语言环境。准备好了吗?我们开始!
应用数据结构
我们要组织JSON请求结构,并通过JSON返回更新页面,我们在HTML文件声明一个合局范围的基本数据结构。该对象要求:
- 包含查询参数的JSON请求,用于Feed view
- 根据用户在Settings view的输入进行更新
require([
//...
], function (parser) {
flickrview = {};
flickrview.QUERY = {
tags: "famous,bridges",
tagmode: "all",
format: "json",
lang: "en-us"
};
//...
});
这就定义完成,任务组件都可以set和get flickrview.QUERY.
FeedView属性
Feed view负责获取和显示最新上传到Flickr上的照片,我们需要一个url和一些参数通过JSONP请求来取得Flickr公共服务:
// Flickr public feed URL to pull recent photo uploads from
requestUrl: "http://api.flickr.com/services/feeds/photos_public.gne",
// JSONP request options and query parameters
requestOptions: {
jsonp: "jsoncallback",
preventCache: true,
timeout: 10000,
query: null
},
请求参数在调用之前将动态设置,更多的Dojo请求参数,参见Dojo request Reference Guide.
参见静态页面,你会发现照片列表需要特别格式化以包括标题、发布时间和任务信息。我们来创建一个适应照片feed模板的属性:
// Create a template string for a photo ListItem
flickrviewItemTemplateString:
'<img src="${photo}" width="80px" height="80px" alt="${title}" style="float:left;"/>' +
'<div class="photoSummary">' +
'<div class="photoTitle">${title}</div>' +
'<div class="publishedTime">${published}</div>' +
'<div class="author troncatedText">${author}</div>' +
'</div><div class="summaryClear"></div>',
我们也定义一个方法替代模板变量:
substitute: function(template,obj) {
return template.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g, function(match,key){
return obj[key];
});
}
继续小部件的引用,初始化工作将在开始方法中完成
//...
refreshButton: null,
feedList: null,
feedHeading: null,
progressIndicator: null,
detailsContainer:null,
detailsHeading:null,
//...
FeedView启动
在解析和创建的子部件都完成之后,Dojo小部件启动任务被调用一次,下面我们来一行行解读:
startup: function() {this.inherited(arguments);
startup方法继承自dojox/mobile/ScrollableView,进而继承自dijit/_WidgetBase.所以我们调用this.inherited(arguments).
Startup是Dojo小部件生命周期的一部分,参见这里更多Dojo小部件生命周期:dijit/_WidgetBase Reference Guide.(http://dojotoolkit.org/reference-guide/dijit/_WidgetBase.html)
来自dijit/registry的byId方法用于查找组件引用:
// retain widgets references
this.refreshButton = registry.byId("refreshButton");
this.feedList = registry.byId("feedList");
this.feedHeading = registry.byId("feedHeading");
this.detailsContainer = registry.byId("detailsContainer");
this.detailsHeading = registry.byId("detailsHeading");
ProgressIndicator是用于表明当前任务正在进行的图像,我们在等视图刷新时会用到。
this.progressIndicator = ProgressIndicator.getInstance();
这里可参考更多使用和自定义ProgressIndicator的信息:Reference Guide.(http://dojotoolkit.org/reference-guide/dojox/mobile/ProgressIndicator.html)
我们给刷新按钮增加点击事件,这里声明的this.refresh方法我们在下一篇定义。注意,使用lang.hitch方法用于确保回调函数this.refresh将在小部件实例的上下文中被调用:
// add click handler to the button that call refresh
this.refreshButton.on("click", lang.hitch(this, this.refresh) );
FeedView刷新
刷新方法负责从Flickr取得照片和更新视图。首先,我们移动列表中的任何内容,然后显示等待动画:
// remove all list items
this.feedList.destroyDescendants();
// reset scroll to make sur progress indicator is visible
this.scrollTo({x:0,y:0});
// add progress indicator
this.feedHeading.set('label',"loading...");
this.feedList.domNode.appendChild(this.progressIndicator.domNode);
this.progressIndicator.start();
现在我们发送一个JSON请求给Flickr:
// request feed from Flickr
this.requestOptions.query = flickrview.QUERY;
scriptRequest.get(this.requestUrl, this.requestOptions).then(lang.hitch(this, this.onFlickrResponse), lang.hitch(this, this.onFlickrError));
真正更新列表的工作是我们的两个回调函数完成的:onFlickrResponse(成功响应)和onFlickrError(异常).
你可以在浏览器中输入这个请求,获取详细数据:http://api.flickr.com/services/feeds/photos_public.gne?tags=famous,bridge&lang=en-us&format=json
处理JSON响应
onFlickrResponse方法处理成功响应,我们一行行了解。首先停止进度示意动画然后更新标题:
// remove progress indicator
this.progressIndicator.stop();
this.feedList.destroyDescendants();
// restore the title
this.feedHeading.set('label','Feeds');
遍历结果项:
// populate the list
array.forEach(result.items, lang.hitch(this, function (resultItem)
为每一项创建dojox/mobile/ListItem并加到队列的末尾:
// Create a new ListItem at the end of the list
var listItem = new ListItem({}).placeAt(this.feedList, "last");
设置样式,使用简单HTML模板注入列表项内容:
// set custom style
domClass.add(listItem.domNode, "photoListItem");
// create and insert content from template and JSON response
listItem.containerNode.innerHTML = this.substitute(this.flickrviewItemTemplateString, {
photo: resultItem.media.m,
title: resultItem.title,
published: locale.format(new Date(resultItem.published), {locale:flickrview.QUERY.lang}),
author: resultItem.author
});
先不理会published属性的格式化,我们在谈到本地化环节会详细说明。
点击列表项会触发切换到详情视图,切换之前我们需要更新详情视图的内容。所以我们给列表项增加点击处理函数:
listItem.onClick = lang.hitch(this, function(){
// update details view before transitioning to it
this.detailsContainer.domNode.innerHTML = resultItem.description.replace(/href=/ig,"target=\"_blank\" href=");
listItem.set("transition","slide");
listItem.transitionTo("details");
});
注意,我们加入target属性来强制所有的链接都打开新浏览页。这在链接到外网站时是最佳的实践方式。
因为我们以编程方式实现跳转,所以设置moveTo属性为#,这样小部件就不会使用自身的跳转动作。
listItem.set("moveTo","#");
异常处理比较简单:停止进度示意动画,在标题栏显示异常信息通知用户。
onFlickrError: function(error) {
// remove progress indicator
this.progressIndicator.stop();
this.feedList.destroyDescendants();
// display error message
this.feedHeading.set('label',error);
alert(error);
}
接下就要测试第一个“可执行版本”的应用了!就差配置应用的本地化日期格式。
使用本地化日期格式
在JSON请求,我们指定返回数据本地化要求,但返回的数据是没有格式化的(像这样原始的形式:2013-09-15T07:57:04Z)。Dojo提供很多功能来本地化你的应用,这里我们使用一个方法来格式化:
published: locale.format(new Date(resultItem.published),{locale:flickrview.QUERY.lang}),
因为我们强制本地化(默认情况下,Dojo使用浏览器的本地化设置),所以需要指定本地化列表,Dojo必须能从配置中加载起来。我们会用到配置参数extraLocale:
dojoConfig = {
async: true,
baseUrl: './',
parseOnLoad: false,
mblHideAddressBar: true,
extraLocale: ["en-us", "fr-fr", "de-de", "it-it", "ko-kr", "pt-br", "es-us", "zh-hk"],
packages: [{
name: "flickrview",
location: "js"
}]
};
最后就是应用启动时的自动刷新:
// Parse the page for widgets
parser.parse();
// refresh at startup
registry.byId("feed").refresh();
所有代码完成,FeedView现在从Flickr获取内容了!点击下面链接查看效果和浏览全部代码。下一节将要实现Settings view修改请求参数。
VIEW DEMO
下载源代码
下载
Part 3 - FlickrView: Implementing FeedView.
============================================
Part 3 END
next
Part 4 - FlickrView: Implementing SettingsView