iScroll-5拉动刷新功能实现与iScroll-4上拉刷新的一点改进
近来在学习移动设备的应用开发,接触了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', {
|
var myScroll = new IScroll('#wrapper', {
//Event: refresh ... |
从上面两者的示例代码对比,以前的声明定义是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上拉刷新的一点改进的更多相关文章
- Android PullToRefreshListView上拉刷新和下拉刷新
PullToRefreshListView实现上拉和下拉刷新有两个步骤: 1.设置刷新方式 pullToRefreshView.setMode(PullToRefreshBase.Mode.BOTH) ...
- iscroll.js实现上拉刷新,下拉加载更多,应用技巧项目实战
上拉刷新,下拉加载更多...仿原生的效果----iscroll是一款做滚动效果的插件,具体介绍我就不废话,看官方文档,我只写下我项目开发的一些用到的用法: (如果不好使,调试你的css,想必是个很蛋疼 ...
- iScroll示例,下拉刷新,上拉刷新
iScroll示例,下拉刷新,上拉刷新 <!DOCTYPE html> <html> <head> <meta http-equiv="Conten ...
- 使用mescroll来实现移动端页面上拉刷新, 下拉加载更多功能
* mescroll请参考官方文档 1. 使用mescroll实现下拉滑动的效果: (仅仅效果, 有的页面不需要刷新数据, 只要你能下拉就行) 代码如下: var mescroll = new MeS ...
- 安卓自带下拉刷新SwipeRefreshLayout加入上拉刷新功能
在项目里面要用到刷新库.曾经都是使用第三方的.只是看到官方出了 SwipeRefreshLayout之后就用SwipeRefreshLayout.可是不知道什么原因官方SwipeRefreshL ...
- SuperSwipeRefreshLayout 一个功能强大的自己定义下拉刷新组件
SuperSwipeRefreshLayout 一个功能强大的自己定义下拉刷新组件. Why? 下拉刷新这样的控件.想必大家用的太多了,比方使用非常多的XListView等. 近期.项目中非常多列表都 ...
- MUI - 上拉刷新/下拉加载
新闻信息列表必备的功能,支持Table,Ul等列表. 以下是DIV版本,在安卓端或者ios端必须使用双webview模式,传送门:http://dev.dcloud.net.cn/mui/pulldo ...
- Android UI之下拉刷新上拉刷新实现
在实际开发中我们经常要用到上拉刷新和下拉刷新,因此今天我写了一个上拉和下拉刷新的demo,有一个自定义的下拉刷新控件 只需要在布局文件中直接引用就可以使用,非常方便,非常使用,以下是源代码: 自定义的 ...
- iOS MJRefresh下拉、上拉刷新自定义以及系统详细讲解
更新: MJRefresh 更新功能,默认根据数据来源 自动显示 隐藏footer,这个功能可以关闭 DoctorTableView.mj_footer.automaticallyHidden = N ...
- iOS--MJRefresh的使用 上拉刷新和下拉加载
1.一般使用MJRefresh 来实现上拉刷新和下拉加载功能 2.MJRefresh 下载地址:https://github.com/CoderMJLee/MJRefresh 3. MJRefresh ...
随机推荐
- linux内核中sys_poll()的简化分析
app:poll or select; kernel: sys_poll(); do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,st ...
- C# 读取oracle 中文乱码的解决方案
用OracleDataAccess.dll访问oracle数据库,遇到中文乱码的情况. 解决方案如下: 1查看字符集编码, 在数据库服务器端 启动 sqlplus SQL->select use ...
- android studio 打开github开源代码
1.最近下载的开源代码全是github来的,一直用eclipse开发,对于android studio来说是全新的 2.在eclipse导入一个工程那是so easy, import选择一下就可以. ...
- Linux下crontab详解
1.crond介绍 crond是Linux下的任务调度命令,让系统定期执行指定程序.crond命令每分钟都会检查是否有要执行的工作,若有要执行的程序便会自动执行. linux下任务调度工作主要分两类: ...
- 子查询注意这几点, 就可以写出好的sql语句
执行sql时子查询的语句一般优先执行 理论上多表查询效率是高于子查询(根据子查询不值一个查询语句可能会有多个from但是多表查询只产生一个from), 但是在oracle中子查询效率一般会高于多表查询
- C#线程同步总结
对于整数数据类型的简单操作,可以用Interlocked类的成员来实现线程同步.对于复杂的线程同步,有以下几个方法: 1.lock关键字: 2.Monitor: 3.同步事件和等待句柄: 4.Mute ...
- 1199: [HNOI2005]汤姆的游戏 - BZOJ
Description 汤姆是个好动的孩子,今天他突然对圆规和直尺来了兴趣.于是他开始在一张很大很大的白纸上画很多很多的矩形和圆.画着画着,一不小心将他的爆米花弄撒了,于是白纸上就多了好多好多的爆米花 ...
- no appropriate service handler found The Connection descriptor used by the client was: localhost:1521:myorcl
参考网址:http://www.2cto.com/database/201205/133542.html http://www.cnblogs.com/kerrycode/p/4244493.html ...
- 团体程序设计天梯赛-练习集L2-005. 集合相似度
L2-005. 集合相似度 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 给定两个整数集合,它们的相似度定义为:Nc/Nt*1 ...
- css3属性整理
浏览器内核:主流内容主要有Mozilla(熟悉的有Firefox,Flock等浏览器).WebKit(熟悉的有Safari.Chrome等浏览器).Opera(Opera浏览器).Trident(讨厌 ...

















