Dojo Mobile 是一个基于 dojo 的用于开发移动应用的组件库,里面提供了许多用来构建移动用户界面的轻量级组件。开发者通过这些组件和皮肤可以开发出跟原生移动应用体验非常接近的移动设备客户端界面。
dojox/mobile/ScrollableView 是一个占满整个移动设备屏幕的容器 Widget,并且可以通过触摸来上下滚动其中的内容。从 Dojo Mobile 1.9 起,它新增了一个新事件 onBeforeScroll 用来响应用户的滚动操作是否正在进行。它的事件参数 e 包含 6 个重要属性:
加上它在 Dojo Mobile 之前的版本里就有的 onTouchEnd 事件,我们可以很方便的实现很多在当今手机应用中用户喜闻乐见的交互模式。
回页首
首先,在页面上新建一个 dojox/mobile/ScrollableView。
清单 1. HTML
<div id="sview" data-dojo-type="dojox.mobile.ScrollableView"> <h1 data-dojo-type="dojox.mobile.Heading" fixed="top">Pull down to refresh</h1> <div id="pullToRefreshPanel" style="display: none;"> <div><div></div></div> </div> <ul id="rlist" data-dojo-type="dojox.mobile.RoundRectList"> <li data-dojo-type="dojox.mobile.ListItem">Item 1</li> …… <li data-dojo-type="dojox.mobile.ListItem">Item 10</li> </ul> </div>
这个 Scrollable View 里包含三个部分:
,相当于
此页面的
Title 。
一个
隐藏的
pullToRefreshPanel div,稍后用来显示用户的下拉效果。 图 1. 初始化页面
然后,定义显示用户下拉效果的 pullToRefreshPanel div。
清单 2. CSS
#pullToRefreshPanel { position: absolute; top: 0px; width: 100%; z-index: 100; font-weight: bold; overflow: hidden; background-color: #E4E7EE; padding-left: 20px; } #pullToRefreshPanel > div { position: inherit; bottom: 12px; padding-left: 22px; width: 100%; height: 100%; color: #6E8098; background-repeat: no-repeat; background-position: bottom left; } #pullToRefreshPanel > div > div { position: absolute; bottom: 4px; } .pullDownToUpdate > div { background-image: url('images/pull-arrow.png'); } .pullDownToUpdate > div > div:before { content: "Please continue to pull down"; } .releaseToUpdate > div { background-image: url('images/release-arrow.png'); } .releaseToUpdate > div > div:before { content: "Please release"; }
其中的两个图片为向下和向上的两个箭头,指示用户此时应该向哪个方向滑动手指。
图 2. 下拉高度未达到 80 像素
图 3. 下拉高度超过 80 像素
最后,添加页面初始化之后需要用到的脚本。
清单 3. JavaScript
require([ "dojo/ready", "dojo/on", "dojo/dom", "dojo/dom-class", "dijit/registry", "dojox/mobile/parser", "dojox/mobile", "dojox/mobile/compat", "dojox/mobile/ScrollableView", "dojox/mobile/Heading", "dojox/mobile/RoundRect", "dojox/mobile/RoundRectList" ], function(ready, on, dom, domClass, registry){ ready(function(){ var pullToRefreshPanel = dom.byId("pullToRefreshPanel"); var scrollableView = registry.byId("sview"); var recordList = registry.byId("rlist"); var pullToRefreshPanelDisplayed = false; var refreshOnTouchEnd = false; var index = 10; var total = 25; var displayPullToRefreshPanel = function() { pullToRefreshPanelDisplayed = true; pullToRefreshPanel.style.display="block"; }; var hidePullToRefreshPanel = function() { pullToRefreshPanelDisplayed = false; pullToRefreshPanel.style.display="none"; }; scrollableView.on("beforescroll", function(evt){ if(evt.beforeTop){ // 显示 pullToRefreshPanel 面板 if(!pullToRefreshPanelDisplayed){ displayPullToRefreshPanel(); } // 根据用户手指的滑动距离调整 pullToRefreshPanel 面板的显示高度 pullToRefreshPanel.style.height= evt.beforeTopHeight + "px"; pullToRefreshPanel.style.top= -evt.beforeTopHeight + "px"; }else{ // 隐藏 pullToRefreshPanel 面板 if(pullToRefreshPanelDisplayed){ hidePullToRefreshPanel(); } } if(evt.beforeTopHeight > 80){ domClass.remove(pullToRefreshPanel, "pullDownToUpdate"); domClass.add(pullToRefreshPanel, "releaseToUpdate"); refreshOnTouchEnd = true; }else{ domClass.remove(pullToRefreshPanel, "releaseToUpdate"); domClass.add(pullToRefreshPanel, "pullDownToUpdate"); refreshOnTouchEnd = false; } }); scrollableView.on("touchend", function(evt){ // 用户手指的滑动操作结束,手指已经抬起离开屏幕 // 隐藏 pullToRefreshPanel 面板 if(pullToRefreshPanelDisplayed){ hidePullToRefreshPanel(); } // 刷新页面 if(refreshOnTouchEnd){ refreshOnTouchEnd = false; // 清空数据列表 registry.byId("rlist").destroy(); var newRecordList = new dojox.mobile.RoundRectList({id:"rlist"}); var remain = total - index; if(remain > 10){ for(var i=0;i<10;i++){ newRecordList.addChild(new dojox.mobile.ListItem({label:"Item "+ ++index})); } } else { // 到达最后一页 for(var i=0;i<remain;i++){ newRecordList.addChild(new dojox.mobile.ListItem({label:"Item "+ ++index})); } newRecordList.addChild(new dojox.mobile.ListItem({label:"No more records"})); index = 0; } scrollableView.addChild(newRecordList); } }); }); });
请注意以上代码中绑定至 ScrollableView 的加粗的新事件。首先,我们用 beforeScroll 来监听用户此时是否正在滑动 ScrollableView,evt.beforeTop 为 true 就表示用户正在向下滑动而且已经超过了 ScrollableView 的最顶端,那么这时应该显示预先隐藏在 ScrollableView 里的 pullToRefreshPanel div 并将它的高度设成 evt.beforeTopHeight,跟用户滑动手指的高度一致。这时候 pullToRefreshPanel 显示的图片是个向下箭头,提示用户“请继续下拉”,那么用户会继续向下滑动手指而不松开。直到用户向下滑动的高度大于 80 个像素,pullToRefreshPanel 显示的图片会变成向上箭头,提示用户“请松手”,那么用户松开手指后就触发了 touchEnd 事件。在 touchEnd 事件的处理函数中先隐藏 pullToRefreshPanel div,然后在 ScrollableView 里删除之前的十条数据并显示接下来的十条数据。这样,就完成了一次下拉刷新的功能,这个过程可以反复发生直到显示最后一页。
图 4. 页面刷新显示第二页的数据
图 5. 页面刷新显示最后一页的数据
接下来,我们举一反三,如果要实现像微信那样,下拉之后并不删除之前的数据,而是在顶部加载新数据,该怎么做呢?
回页首
很简单,只需要把脚本里 touchEnd 事件的处理函数对应的地方改成这样就行了:
清单 4. JavaScript
if(refreshOnTouchEnd){ refreshOnTouchEnd = false; // 这次不用清空数据列表 var recordListDom = recordList.domNode; var remain = total - index; if(remain > 10){ for(var i=0;i<10;i++){ recordListDom.insertBefore(new dojox.mobile.ListItem({label:"Item "+ ++index}).domNode, recordListDom.firstChild); } } else { // 到达最后一页 for(var i=0;i<remain;i++){ recordListDom.insertBefore(new dojox.mobile.ListItem({label:"Item "+ ++index}).domNode, recordListDom.firstChild); } recordListDom.insertBefore(new dojox.mobile.ListItem({label:"No more records"}).domNode, recordListDom.firstChild); } }
图 6. 下拉加载到最后一页的效果
现在,我们反过来,把下拉变成上拉,在界面底端实现刷新又该怎么做?
回页首
还是在下拉刷新的代码基础上进行改动,需要替换的代码如下:
图 7. 上拉高度未达到 80 像素
图 8. 上拉高度超过 80 像素
最后一种情况是上拉加载更多,比下拉加载更多的功能实现起来要简单,因为不是在列表最顶端插入元素,而是在末尾。
回页首
在上拉刷新的代码基础上,只需要把脚本里 touchEnd 事件的处理函数对应的地方改成这样就行了:
清单 5. JavaScript
if(refreshOnTouchEnd){ refreshOnTouchEnd = false; // 这次不用清空数据列表 var remain = total - index; if(remain > 10){ for(var i=0;i<10;i++){ recordList.addChild(new dojox.mobile.ListItem({label:"Item "+ ++index})); } } else { // 到达最后一页 for(var i=0;i<remain;i++){ recordList.addChild(new dojox.mobile.ListItem({label:"Item "+ ++index})); } recordList.addChild(new dojox.mobile.ListItem({label:"No more records"})); } }
图 9. 上拉加载到最后一页的效果
回页首
本文介绍了如何使用 Dojo Mobile 1.9 的新特性在移动应用中方便快速的实现常用的分页显示功能,然后举一反三,一并介绍了由此扩展的另外三种交互模式。通过学习具体的示例代码,读者可以在自己的查询功能中灵活运用这些方法。
回页首
实例代码中的文件可以直接拷贝至 Dojo 源代码库里的 dojox/mobile/tests 路径下,双击运行。
回页首
描述 | 名字 | 大小 |
---|---|---|
示例代码 | codes.zip | 7KB |