近来在学习移动设备的应用开发,接触了jQuery mobile,在网上查阅相关资料时发现一个叫”iScroll“的小插件。其实这个iScroll插件跟jQuery mobile没有多大关系,并不是基于jQuery mobile类库开发的js插件,是一个独立的js插件,使用它时不必预先引用jquery或jquery mobile类库。关于iScroll的详细介绍可以去它的官网了解或者去GitHub(https://github.com/cubiq/iscroll/)下载它的源码学习。iScroll现在已经更新为iScroll-5,但并没有加入太多新的功能,只是对前一个版本iScroll-4进行重构优化与修复,而且官方消息说不再对iScroll-4进行维护和技术支持,建议使用新版本。官方说法如下:

iScroll-5与iScroll-4的差别还挺大的,首先在声明定义上写法就不一样了。

iScroll-4: iScroll-5:
var myScroll = new iScroll('wrapper', {
useTransition: true,
topOffset: pullDownOffset,
onRefresh: function () {
...
},
   onScrollStart: function () {
     ...
   },
   onScrollMove: function () {
     ...
   },
   onScrollEnd: function () {
     ...
   }
  
   ....
});
var myScroll = new IScroll('#wrapper', {
mouseWheel: true,
scrollbars: true,
startY:-pullDownOffset
...
}); //Event: scroll start
myScroll.on("scrollStart", function() {
...
}); //Event: scroll
myScroll.on('scroll', function(){
...
}); //Event: scrollEnd
myScroll.on("scrollEnd", function() {
...
});
//Event: refresh
myScroll.on("refresh", function() {
...
});
...

从上面两者的示例代码对比,以前的声明定义是new iScroll('wrapper'...),现在变为new IScroll('#wrapper'...),类名变为大写I开头了,容器的Id要加上前缀#,某些参数名称改变了(以前的topOffset变为startY和startX),关键是事件(event)不再是从options参数中指定,而是用on去注册等等。

还有一个重大的不同是,iScroll-5按照功能点不同自身又划分为不同的版本,官方划分如下:

还有其他的差异就不再逐个列出了,大家可以到官网去了解。

其实iScroll之所以吸引我,主要是在iScroll-4中的demo里面有一个叫”pull-to-refresh“的示例,也就是我们说拉动更新,包括列表内容的下拉和上拉更新。这个功能在触摸的移动应用上经常用到,可以不夸张的说是必不可少的。但这个重要的示例在新版iScroll-5的demo中却找不到了。不知什么原因作者将它去掉了(据说iScroll-4的pull-to-refresh这个示例并不是作者的杰作),我在网上找了很久都没发现有关于iScroll-5官方的pull-to-refresh示例,个别实现的例子倒也是有一些,但效果都不是很令人满意。为了加深和巩固对iScroll的学习,本人就参考iScroll-4的pull-to-refresh示例来实现iScroll-5的拉动刷新功能,同时也对iScroll-4的pull-to-refresh示例根据个人需求进行了一点改进。

首先给出iScroll-4的pull-to-refresh示例改动后的代码:

 <script type="text/javascript">

 var myScroll,
pullDownEl, pullDownOffset,
pullUpEl, pullUpOffset, _maxScrollY;
var generatedCount = 0; function pullDownAction () {
setTimeout(function () { // <-- Simulate network congestion, remove setTimeout from production!
var el, li, i;
el = document.getElementById('thelist'); for (i=0; i<3; i++) {
li = document.createElement('li');
li.innerHTML = '(Pull down) Generated row ' + (++generatedCount);//Firefox does not suppose innerText, use innerHTML instead.
el.insertBefore(li, el.childNodes[0]);
} myScroll.refresh(); // Remember to refresh when contents are loaded (ie: on ajax completion)
}, 1000); // <-- Simulate network congestion, remove setTimeout from production!
} function pullUpAction () {
setTimeout(function () { // <-- Simulate network congestion, remove setTimeout from production!
var el, li, i;
el = document.getElementById('thelist'); for (i=0; i<3; i++) {
li = document.createElement('li');
li.innerHTML = '(Pull up) Generated row ' + (++generatedCount);//Firefox does not suppose innerText, use innerHTML instead.
el.appendChild(li, el.childNodes[0]);
} myScroll.refresh(); // Remember to refresh when contents are loaded (ie: on ajax completion)
}, 1000); // <-- Simulate network congestion, remove setTimeout from production!
} function loaded() {
pullDownEl = document.getElementById('pullDown');
pullDownOffset = pullDownEl.offsetHeight;
pullUpEl = document.getElementById('pullUp');
pullUpOffset = pullUpEl.offsetHeight; myScroll = new iScroll('wrapper', {
useTransition: true,
topOffset: pullDownOffset,
onRefresh: function () {
console.log('maxScrollY-0:'+this.maxScrollY);
_maxScrollY = this.maxScrollY = this.maxScrollY + pullUpOffset;
console.log('maxScrollY-1:'+this.maxScrollY);
if (pullDownEl.className.match('loading')) {
pullDownEl.className = '';
pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Pull down to refresh...';
} else if (pullUpEl.className.match('loading')) {
pullUpEl.className = '';
pullUpEl.querySelector('.pullUpLabel').innerHTML = 'Pull up to load more...';
this.scrollTo(0,this.maxScrollY,0);
}
},
onScrollMove: function () {
console.log('maxScrollY-3:'+this.maxScrollY);
if (this.y > 5 && !pullDownEl.className.match('flip')) {
pullDownEl.className = 'flip';
pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Release to refresh...';
this.minScrollY = 0;
} else if (this.y < 5 && pullDownEl.className.match('flip')) {
pullDownEl.className = '';
pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Pull down to refresh...';
this.minScrollY = -pullDownOffset;
} else if (this.y <= (_maxScrollY - pullUpOffset) && !pullUpEl.className.match('flip')) {
pullUpEl.className = 'flip';
pullUpEl.querySelector('.pullUpLabel').innerHTML = 'Release to refresh...';
this.maxScrollY = this.maxScrollY - pullUpOffset;
} else if (this.y > (_maxScrollY - pullUpOffset) && pullUpEl.className.match('flip')) {
pullUpEl.className = '';
pullUpEl.querySelector('.pullUpLabel').innerHTML = 'Pull up to load more...';
this.maxScrollY = this.maxScrollY + pullUpOffset;
}
},
onScrollEnd: function () {
if (pullDownEl.className.match('flip')) {
pullDownEl.className = 'loading';
pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Loading...';
console.log('pull down---scroll end');
pullDownAction(); // Execute custom function (ajax call?)
} else if (pullUpEl.className.match('flip')) {
pullUpEl.className = 'loading';
pullUpEl.querySelector('.pullUpLabel').innerHTML = 'Loading...';
console.log('pull up---scroll end');
pullUpAction(); // Execute custom function (ajax call?)
}
}
}); setTimeout(function () { document.getElementById('wrapper').style.left = '0'; }, 800);
} document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false); document.addEventListener('DOMContentLoaded', function () { setTimeout(loaded, 200); }, false);
</script>

上面代码高亮标注(黄色底色)的地方是主要的改动点,对于第15,30行标注的innerHTML原来例子是innerText,但我发现在firefox运行后新增的li会显示不了内容(应该是firebox不支持innerText),改为innerHTML后就正常显示了。其他处的改动主要是针对maxScrollY这个变量,这样改主要是为了让列表内容滚动到底部时上拉前不显示提示栏。

iScroll-4 示例改动前: iScroll-4 示例改动后:

下面参照iScroll-4改动后的push-to-refresh示例来实现iScroll-5的拉动刷新功能。使用iScroll-5来实现的话,要引用的js类库是iScroll-5细分后的iscroll-probe.js,按照前面的划分介绍,此细分版本主要是为了探查当前滚动位置(x,y)。在实现过程中我发现类库有一小处源码是需要改动的,主要是解决鼠标滑轮向顶部滚动时,不显示下拉提示栏(这个问题在iScroll-4下是不存在的,应该跟iScroll-5去掉了minScrollY这个变量有关),我们希望在下拉时才会出现提示栏。

解决办法其实也不复杂,只需改动一下iscroll-probe.js文件里面的第1122行处的一小段代码。如下图:

之所以这样修改,主要是参考iScroll-4里面的源码。如下图:

好,源文件iscroll-probe.js的修改就完成了,下面给出iScroll-5拉动刷新功能的页面js代码:

 <script type="text/javascript">

 var myScroll,
pullDownEl, pullDownOffset,
pullUpEl, pullUpOffset, _maxScrollY; var generatedCount = 0; function pullDownAction(){
setTimeout(function () { // <-- Simulate network congestion, remove setTimeout from production!
var el, li, i;
el = document.querySelector('#scroller ul'); for (i=0; i<3; i++) {
li = document.createElement('li');
li.innerHTML = '(Pull down) Generated row ' + (++generatedCount);//Firefox does not suppose innerText, use innerHTML instead.
el.insertBefore(li, el.childNodes[0]);
}
if(myScroll){
myScroll.refresh(); // Remember to refresh when contents are loaded (ie: on ajax completion)
}
}, 1000); // <-- Simulate network congestion, remove setTimeout from production!
} function pullUpAction () {
setTimeout(function () { // <-- Simulate network congestion, remove setTimeout from production!
var el, li, i;
el = document.querySelector('#scroller ul'); for (i=0; i<3; i++) {
li = document.createElement('li');
li.innerHTML = '(Pull up) Generated row ' + (++generatedCount);//Firefox does not suppose innerText, use innerHTML instead.
el.appendChild(li, el.childNodes[0]);
}
if(myScroll){
myScroll.refresh(); // Remember to refresh when contents are loaded (ie: on ajax completion)
}
}, 1000); // <-- Simulate network congestion, remove setTimeout from production!
} function loaded() {
pullDownEl = document.querySelector('#pullDown');
if (pullDownEl) {
pullDownOffset = pullDownEl.offsetHeight;
} else {
pullDownOffset = 0;
}
pullUpEl = document.querySelector('#pullUp');
if (pullUpEl) {
pullUpOffset = pullUpEl.offsetHeight;
} else {
pullUpOffset = 0;
} console.log('pullDownOffset:'+pullDownOffset);
console.log('pullUpOffset:'+pullUpOffset); //Options of IScroll
var myOptions = {
mouseWheel: true,
scrollbars: true,
fadeScrollbars: true,
probeType:1,
startY:-pullDownOffset
};
myScroll = new IScroll('#wrapper',myOptions);
console.log('maxScrollY-1:'+myScroll.maxScrollY);
_maxScrollY = myScroll.maxScrollY = myScroll.maxScrollY + pullUpOffset;
console.log('maxScrollY-2:'+myScroll.maxScrollY); var isScrolling = false; //Event: scrollStart
myScroll.on("scrollStart", function() {
if(this.y==this.startY){
isScrolling = true;
}
console.log('start-y:'+this.y);
}); //Event: scroll
myScroll.on('scroll', function(){
if (this.y >= 5 && pullDownEl && !pullDownEl.className.match('flip')) {
pullDownEl.className = 'flip';
pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Release to refresh';
//this.minScrollY = 0;
} else if (this.y < 5 && pullDownEl && pullDownEl.className.match('flip')) {
pullDownEl.className = '';
pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Pull down to refresh';
//this.minScrollY = -pullDownOffset;
}else if (this.y <= (_maxScrollY - pullUpOffset) && pullUpEl && !pullUpEl.className.match('flip')) {
pullUpEl.className = 'flip';
pullUpEl.querySelector('.pullUpLabel').innerHTML = 'Release to refresh';
//this.maxScrollY = this.maxScrollY;
this.maxScrollY = this.maxScrollY - pullUpOffset;
} else if (this.y > (_maxScrollY - pullUpOffset) && pullUpEl && pullUpEl.className.match('flip')) {
pullUpEl.className = '';
pullUpEl.querySelector('.pullUpLabel').innerHTML = 'Pull up to load more';
//this.maxScrollY = pullUpOffset;
this.maxScrollY = this.maxScrollY + pullUpOffset;
} console.log('y:'+this.y);
}); //Event: scrollEnd
myScroll.on("scrollEnd", function() {
console.log('scroll end');
console.log('directionY:'+this.directionY);
console.log('y1:'+this.y);
console.log('maxScrollY-3:'+this.maxScrollY);
if (pullDownEl && !pullDownEl.className.match('flip') && this.y > this.options.startY) {
console.log('resume');
this.scrollTo(0, this.options.startY,800);
}
else if (pullDownEl && pullDownEl.className.match('flip')){
pullDownEl.className = 'loading';
pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Loading...';
// Execute custom function (ajax call?)
if (isScrolling) {
console.log('before pull down action:'+this.y);
pullDownAction();
console.log('after pull down action:'+this.y);
}
}
else if (pullUpEl && pullUpEl.className.match('flip')) {
console.log('pull up loading');
pullUpEl.className = 'loading';
pullUpEl.querySelector('.pullUpLabel').innerHTML = 'Loading...';
// Execute custom function (ajax call?)
if (isScrolling) {
console.log('before pull up action:'+this.y);
pullUpAction();
console.log('after pull up action:'+this.y);
}
}
isScrolling = false;
}); //Event: refresh
myScroll.on("refresh", function() { console.log('maxScrollY-4:'+this.maxScrollY);
_maxScrollY = this.maxScrollY = this.maxScrollY+pullUpOffset;
console.log('maxScrollY-5:'+this.maxScrollY); if (pullDownEl && pullDownEl.className.match('loading')) {
pullDownEl.className = '';
pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Pull down to refresh';
this.scrollTo(0,this.options.startY,0);
} else if (pullUpEl && pullUpEl.className.match('loading')) {
pullUpEl.className = '';
pullUpEl.querySelector('.pullUpLabel').innerHTML = 'Pull up to load more';
this.scrollTo(0,this.maxScrollY,0);
} console.log('refresh finished!');
}); setTimeout(function () { document.getElementById('wrapper').style.left = '0'; }, 500); } document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false); </script>

运行效果:

 iScroll-4:
 iScroll-5:

后话:按照官网的介绍iScroll-5比iScroll-4更快,性能更好。但在上面的拉动刷新的示例中,iScroll-5在firefox中运行时比iScroll-4要占用更多的CPU,感觉iScroll-4要流畅得多,但仅限于拉动功能的比较,至于iScroll的其他功能没有测试对比过,所以也不敢以偏概全地断言说iScroll-5的性能就比上iScroll-4。有兴趣的朋友可以去测试一下,测完后给我分享一下结果,谢谢!

iScroll-5拉动刷新功能实现与iScroll-4上拉刷新的一点改进的更多相关文章

  1. Android PullToRefreshListView上拉刷新和下拉刷新

    PullToRefreshListView实现上拉和下拉刷新有两个步骤: 1.设置刷新方式 pullToRefreshView.setMode(PullToRefreshBase.Mode.BOTH) ...

  2. iscroll.js实现上拉刷新,下拉加载更多,应用技巧项目实战

    上拉刷新,下拉加载更多...仿原生的效果----iscroll是一款做滚动效果的插件,具体介绍我就不废话,看官方文档,我只写下我项目开发的一些用到的用法: (如果不好使,调试你的css,想必是个很蛋疼 ...

  3. iScroll示例,下拉刷新,上拉刷新

    iScroll示例,下拉刷新,上拉刷新 <!DOCTYPE html> <html> <head> <meta http-equiv="Conten ...

  4. 使用mescroll来实现移动端页面上拉刷新, 下拉加载更多功能

    * mescroll请参考官方文档 1. 使用mescroll实现下拉滑动的效果: (仅仅效果, 有的页面不需要刷新数据, 只要你能下拉就行) 代码如下: var mescroll = new MeS ...

  5. 安卓自带下拉刷新SwipeRefreshLayout加入上拉刷新功能

    在项目里面要用到刷新库.曾经都是使用第三方的.只是看到官方出了  SwipeRefreshLayout之后就用SwipeRefreshLayout.可是不知道什么原因官方SwipeRefreshL ...

  6. SuperSwipeRefreshLayout 一个功能强大的自己定义下拉刷新组件

    SuperSwipeRefreshLayout 一个功能强大的自己定义下拉刷新组件. Why? 下拉刷新这样的控件.想必大家用的太多了,比方使用非常多的XListView等. 近期.项目中非常多列表都 ...

  7. MUI - 上拉刷新/下拉加载

    新闻信息列表必备的功能,支持Table,Ul等列表. 以下是DIV版本,在安卓端或者ios端必须使用双webview模式,传送门:http://dev.dcloud.net.cn/mui/pulldo ...

  8. Android UI之下拉刷新上拉刷新实现

    在实际开发中我们经常要用到上拉刷新和下拉刷新,因此今天我写了一个上拉和下拉刷新的demo,有一个自定义的下拉刷新控件 只需要在布局文件中直接引用就可以使用,非常方便,非常使用,以下是源代码: 自定义的 ...

  9. iOS MJRefresh下拉、上拉刷新自定义以及系统详细讲解

    更新: MJRefresh 更新功能,默认根据数据来源 自动显示 隐藏footer,这个功能可以关闭 DoctorTableView.mj_footer.automaticallyHidden = N ...

  10. iOS--MJRefresh的使用 上拉刷新和下拉加载

    1.一般使用MJRefresh 来实现上拉刷新和下拉加载功能 2.MJRefresh 下载地址:https://github.com/CoderMJLee/MJRefresh 3. MJRefresh ...

随机推荐

  1. shell脚本编程之for语句、if语句使用介绍

    介绍了shell脚本编程之for语句.if语句的使用方法. 上部: 面向过程: 顺序执行 选择执行: if, case 循环执行: for, while, until 一.for语句 格式:      ...

  2. Spark Streaming揭秘 Day19 架构设计和运行机制

    Spark Streaming揭秘 Day19 架构设计和运行机制 今天主要讨论一些SparkStreaming设计的关键点,也算做个小结. DStream设计 首先我们可以进行一个简单的理解:DSt ...

  3. spark 1.3.0下的问题

    1.在spark SQL的一个test中 无论是registerAsTable还是registerTempTable 都会有问题,经过查找各种资料,采用如下的方式: val sqlCon=new or ...

  4. Python 中的引用和类属性的初步理解

    最近对Python 的对象引用机制稍微研究了一下,留下笔记,以供查阅. 首先有一点是明确的:「Python 中一切皆对象」. 那么,这到底意味着什么呢? 如下代码: #!/usr/bin/env py ...

  5. 第一章 基本的SQL语句 (SQL基础)

    1. 查询数据库系统时间,常以服务器默认的格式进行显示(根据数据库的字符集而定): 注意:dual 为数据库中的虚表,隶属于管理员 sys 用户,但所有的用户都可以访问:无实际意义,仅充当select ...

  6. 【maven项目结构】module 生成独立的jar

    生成jar 生成jar的过程会出现以下问题: clean完了之后就会出现以下问题: install [INFO] Scanning for projects... [INFO] [INFO] ---- ...

  7. easyui 文本框 显示提示信息data-options="prompt:'格式:水箱支架-京东汽配店铺-图集(大图/图集6)'"

    <tr> <td>图集6:</td> <td> <input class="easyui-textbox" data-opti ...

  8. 在PyCharm里配置SubVersion

    1.如果PyCharm不支持svn ,那么下载svn命令行安装包,下载地址:http://sourceforge.net/projects/win32svn/ 例如:安装到 D:\software\s ...

  9. springMVC数据封装成POJO

    springMVC把前台的数据封装为POJO与struts2的封装形式不同.struts2需要在控制器声明需封装的POJO,而springMVC不需要任何准备工作,只需在相应的方法的参数中加上需封装的 ...

  10. Hibernate简介2

    一.主配置 ◆查询缓存,同下面讲的缓存不太一样,它是针对HQL语句的缓存,即完全一样的语句再次执行时可以利用缓存数据.但是,查询缓存在一个交易系统(数据变更频繁,查询条件相同的机率并不大)中可能会起反 ...