zoukankan      html  css  js  c++  java
  • 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', {
        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示例改动后的代码:

      1 <script type="text/javascript">
      2 
      3 var myScroll,
      4     pullDownEl, pullDownOffset,
      5     pullUpEl, pullUpOffset, _maxScrollY;
      6 var generatedCount = 0;
      7 
      8 function pullDownAction () {
      9     setTimeout(function () {    // <-- Simulate network congestion, remove setTimeout from production!
     10         var el, li, i;
     11         el = document.getElementById('thelist');
     12 
     13         for (i=0; i<3; i++) {
     14             li = document.createElement('li');
     15             li.innerHTML = '(Pull down) Generated row ' + (++generatedCount);//Firefox  does not suppose innerText, use innerHTML instead.
     16             el.insertBefore(li, el.childNodes[0]);
     17         }
     18         
     19         myScroll.refresh();        // Remember to refresh when contents are loaded (ie: on ajax completion)
     20     }, 1000);    // <-- Simulate network congestion, remove setTimeout from production!
     21 }
     22 
     23 function pullUpAction () {
     24     setTimeout(function () {    // <-- Simulate network congestion, remove setTimeout from production!
     25         var el, li, i;
     26         el = document.getElementById('thelist');
     27 
     28         for (i=0; i<3; i++) {
     29             li = document.createElement('li');
     30             li.innerHTML = '(Pull up) Generated row ' + (++generatedCount);//Firefox  does not suppose innerText, use innerHTML instead.
     31             el.appendChild(li, el.childNodes[0]);
     32         }
     33         
     34         myScroll.refresh();        // Remember to refresh when contents are loaded (ie: on ajax completion)
     35     }, 1000);    // <-- Simulate network congestion, remove setTimeout from production!
     36 }
     37 
     38 function loaded() {
     39     pullDownEl = document.getElementById('pullDown');
     40     pullDownOffset = pullDownEl.offsetHeight;
     41     pullUpEl = document.getElementById('pullUp');    
     42     pullUpOffset = pullUpEl.offsetHeight;
     43     
     44     
     45     myScroll = new iScroll('wrapper', {
     46         useTransition: true,
     47         topOffset: pullDownOffset,
     48         onRefresh: function () {
     49             console.log('maxScrollY-0:'+this.maxScrollY);
     50             _maxScrollY = this.maxScrollY = this.maxScrollY + pullUpOffset;
     51             console.log('maxScrollY-1:'+this.maxScrollY);
     52             if (pullDownEl.className.match('loading')) {
     53                 pullDownEl.className = '';
     54                 pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Pull down to refresh...';
     55             } else if (pullUpEl.className.match('loading')) {
     56                 pullUpEl.className = '';
     57                 pullUpEl.querySelector('.pullUpLabel').innerHTML = 'Pull up to load more...';
     58                 this.scrollTo(0,this.maxScrollY,0);
     59             }
     60         },
     61         onScrollMove: function () {
     62             console.log('maxScrollY-3:'+this.maxScrollY);
     63             if (this.y > 5 && !pullDownEl.className.match('flip')) {
     64                 pullDownEl.className = 'flip';
     65                 pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Release to refresh...';
     66                 this.minScrollY = 0;
     67             } else if (this.y < 5 && pullDownEl.className.match('flip')) {
     68                 pullDownEl.className = '';
     69                 pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Pull down to refresh...';
     70                 this.minScrollY = -pullDownOffset;
     71             } else if (this.y <= (_maxScrollY - pullUpOffset) && !pullUpEl.className.match('flip')) {
     72                 pullUpEl.className = 'flip';
     73                 pullUpEl.querySelector('.pullUpLabel').innerHTML = 'Release to refresh...';
     74                 this.maxScrollY = this.maxScrollY - pullUpOffset;
     75             } else if (this.y > (_maxScrollY - pullUpOffset) && pullUpEl.className.match('flip')) {
     76                 pullUpEl.className = '';
     77                 pullUpEl.querySelector('.pullUpLabel').innerHTML = 'Pull up to load more...';
     78                 this.maxScrollY = this.maxScrollY + pullUpOffset;
     79             }
     80         },
     81         onScrollEnd: function () {
     82             if (pullDownEl.className.match('flip')) {
     83                 pullDownEl.className = 'loading';
     84                 pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Loading...';                
     85                 console.log('pull down---scroll end');
     86                 pullDownAction();    // Execute custom function (ajax call?)
     87             } else if (pullUpEl.className.match('flip')) {
     88                 pullUpEl.className = 'loading';
     89                 pullUpEl.querySelector('.pullUpLabel').innerHTML = 'Loading...';
     90                 console.log('pull up---scroll end');                
     91                 pullUpAction();    // Execute custom function (ajax call?)
     92             }
     93         }
     94     });
     95     
     96     
     97     setTimeout(function () { document.getElementById('wrapper').style.left = '0'; }, 800);
     98 }
     99 
    100 document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false);
    101 
    102 document.addEventListener('DOMContentLoaded', function () { setTimeout(loaded, 200); }, false);
    103 </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代码:

      1 <script type="text/javascript">
      2 
      3 var myScroll, 
      4     pullDownEl, pullDownOffset,
      5     pullUpEl, pullUpOffset, _maxScrollY;
      6     
      7 var generatedCount = 0;
      8 
      9 function pullDownAction(){
     10         setTimeout(function () {    // <-- Simulate network congestion, remove setTimeout from production!
     11             var el, li, i;
     12             el = document.querySelector('#scroller ul');
     13     
     14             for (i=0; i<3; i++) {
     15                 li = document.createElement('li');
     16                 li.innerHTML = '(Pull down) Generated row ' + (++generatedCount);//Firefox  does not suppose innerText, use innerHTML instead.
     17                 el.insertBefore(li, el.childNodes[0]);
     18             }
     19             if(myScroll){
     20                 myScroll.refresh();        // Remember to refresh when contents are loaded (ie: on ajax completion)
     21             }
     22         }, 1000);    // <-- Simulate network congestion, remove setTimeout from production!
     23 }
     24 
     25 function pullUpAction () {
     26     setTimeout(function () {    // <-- Simulate network congestion, remove setTimeout from production!
     27         var el, li, i;
     28         el = document.querySelector('#scroller ul');
     29 
     30         for (i=0; i<3; i++) {
     31             li = document.createElement('li');
     32             li.innerHTML = '(Pull up) Generated row ' + (++generatedCount);//Firefox  does not suppose innerText, use innerHTML instead.
     33             el.appendChild(li, el.childNodes[0]);
     34         }
     35         if(myScroll){
     36             myScroll.refresh();        // Remember to refresh when contents are loaded (ie: on ajax completion)
     37         }
     38     }, 1000);    // <-- Simulate network congestion, remove setTimeout from production!
     39 }
     40 
     41 function loaded() {
     42     pullDownEl = document.querySelector('#pullDown');
     43     if (pullDownEl) {
     44         pullDownOffset = pullDownEl.offsetHeight;
     45     } else {
     46         pullDownOffset = 0;
     47     }
     48     pullUpEl = document.querySelector('#pullUp');    
     49     if (pullUpEl) {
     50         pullUpOffset = pullUpEl.offsetHeight;
     51     } else {
     52         pullUpOffset = 0;
     53     }
     54     
     55     console.log('pullDownOffset:'+pullDownOffset);
     56     console.log('pullUpOffset:'+pullUpOffset);
     57     
     58     //Options of IScroll
     59     var myOptions = {
     60             mouseWheel: true,
     61             scrollbars: true,
     62             fadeScrollbars: true,
     63             probeType:1,
     64             startY:-pullDownOffset
     65         };
     66     myScroll = new IScroll('#wrapper',myOptions);
     67     console.log('maxScrollY-1:'+myScroll.maxScrollY);
     68     _maxScrollY = myScroll.maxScrollY = myScroll.maxScrollY + pullUpOffset;
     69     console.log('maxScrollY-2:'+myScroll.maxScrollY);
     70     
     71     var isScrolling = false;
     72     
     73     //Event: scrollStart
     74     myScroll.on("scrollStart", function() {
     75         if(this.y==this.startY){
     76             isScrolling = true;
     77         }
     78         console.log('start-y:'+this.y);
     79     });
     80     
     81     //Event: scroll
     82     myScroll.on('scroll', function(){
     83         if (this.y >= 5 && pullDownEl && !pullDownEl.className.match('flip')) {
     84             pullDownEl.className = 'flip';
     85             pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Release to refresh';
     86             //this.minScrollY = 0;
     87         } else if (this.y < 5  && pullDownEl && pullDownEl.className.match('flip')) {
     88             pullDownEl.className = '';
     89             pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Pull down to refresh';
     90             //this.minScrollY = -pullDownOffset;
     91         }else if (this.y <= (_maxScrollY - pullUpOffset) && pullUpEl && !pullUpEl.className.match('flip')) {
     92             pullUpEl.className = 'flip';
     93             pullUpEl.querySelector('.pullUpLabel').innerHTML = 'Release to refresh';
     94             //this.maxScrollY = this.maxScrollY;
     95             this.maxScrollY = this.maxScrollY - pullUpOffset;
     96         } else if (this.y > (_maxScrollY - pullUpOffset) && pullUpEl && pullUpEl.className.match('flip')) {
     97             pullUpEl.className = '';
     98             pullUpEl.querySelector('.pullUpLabel').innerHTML = 'Pull up to load more';
     99             //this.maxScrollY = pullUpOffset;
    100             this.maxScrollY = this.maxScrollY + pullUpOffset;
    101         }
    102                     
    103         console.log('y:'+this.y);
    104     });
    105     
    106     //Event: scrollEnd
    107     myScroll.on("scrollEnd", function() {
    108         console.log('scroll end'); 
    109         console.log('directionY:'+this.directionY);
    110         console.log('y1:'+this.y);
    111         console.log('maxScrollY-3:'+this.maxScrollY);
    112         if (pullDownEl && !pullDownEl.className.match('flip') && this.y > this.options.startY) {
    113             console.log('resume'); 
    114             this.scrollTo(0, this.options.startY,800);
    115           }
    116         else if (pullDownEl && pullDownEl.className.match('flip')){
    117                 pullDownEl.className = 'loading';
    118                 pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Loading...';                
    119                 // Execute custom function (ajax call?)
    120                 if (isScrolling) {
    121                     console.log('before pull down action:'+this.y); 
    122                     pullDownAction();
    123                       console.log('after pull down action:'+this.y); 
    124                   }
    125         }
    126         else if (pullUpEl && pullUpEl.className.match('flip')) {
    127                 console.log('pull up loading'); 
    128                 pullUpEl.className = 'loading';
    129                 pullUpEl.querySelector('.pullUpLabel').innerHTML = 'Loading...';    
    130                 // Execute custom function (ajax call?)
    131                 if (isScrolling) {            
    132                     console.log('before pull up action:'+this.y); 
    133                     pullUpAction();    
    134                     console.log('after pull up action:'+this.y); 
    135                 }
    136         }
    137         isScrolling = false;
    138     });
    139     
    140     //Event: refresh
    141     myScroll.on("refresh", function() {
    142           
    143          console.log('maxScrollY-4:'+this.maxScrollY);
    144          _maxScrollY = this.maxScrollY = this.maxScrollY+pullUpOffset;
    145          console.log('maxScrollY-5:'+this.maxScrollY);
    146          
    147          if (pullDownEl  && pullDownEl.className.match('loading')) {
    148                 pullDownEl.className = '';
    149                 pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Pull down to refresh';
    150                 this.scrollTo(0,this.options.startY,0);
    151          } else if (pullUpEl && pullUpEl.className.match('loading')) {
    152                 pullUpEl.className = '';
    153                 pullUpEl.querySelector('.pullUpLabel').innerHTML = 'Pull up to load more';
    154                 this.scrollTo(0,this.maxScrollY,0);
    155          }
    156          
    157          console.log('refresh finished!'); 
    158     });
    159     
    160     setTimeout(function () { document.getElementById('wrapper').style.left = '0'; }, 500);
    161     
    162 }
    163 
    164 document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false);
    165 
    166 </script>

    运行效果:

     iScroll-4:
     iScroll-5:

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

  • 相关阅读:
    Angular @Input讲解及用法
    跨浏览器窗口通讯 ,7种方式
    map和forEach的区别
    纯CSS圆环与圆
    如何理解时间复杂度和空间复杂度
    毁灭
    P1631 序列合并
    plotly dash
    Tkinter
    mysql 和 sqlalchemy 的一个测试环境
  • 原文地址:https://www.cnblogs.com/yghost/p/4230708.html
Copyright © 2011-2022 走看看