H5基于iScroll实现下拉刷新,上拉加载更多.... - 流浪的诗人

时间:2024-02-15 19:14:20

H5基于iScroll实现下拉刷新,上拉加载更多....

2016-06-20 09:27  流浪的诗人  阅读(16201)  评论(4编辑  收藏  举报
1、初识iScroll 
最新版本已经更新到5.0,官网:http://cubiq.org/iscroll-5
iScroll 4 这个版本完全重写了iScroll这个框架的原始代码。这个项目的产生完全是因为移动版webkit浏览器(诸如iPhone,iPad,Android 这些系统上广泛使用)提供了一种本地化的方式来对一个限定了高度和宽度的元素的内容进行滑动。
很不幸的是,这种情况下所有的web应用的页面就不能够包含具有position:absolute的头、页尾或者是一个内容可滚动的中间区域。
然而,Android系统最新修订版已经可以支持这种功能了(尽管支持的力度还不是特别好),Apple公司似乎不太情愿将one-finger滑动事件运用到div元素上。
除了以前版本的iScroll的特性以外,iScroll 4还包括如下的特性:
     (1)缩放(Pinch/Zoom)
    (2)拉动刷新(Pull up/down to refresh)
    (3)速度和性能提升
    (4)精确捕捉元素
    (5)自定义滚动条

2、使用技巧

      2.1、引用iScroll.js和index.js

<script src="./js/iscroll.js"></script>
<script src="./js/index.js"></script>

 iscroll.js为下拉刷新原生文件;

 index.js为自己整理的页面脚本文件,用于初始化iScroll对象,在初始化时添加两个事件监听:touchMove、DOMContentLoaded。

      2.2、搭建HTML主体 结构,如下代码:

<div id="wrapper"> 
   <ul>
      <li></li> ..... 
   </ul> 
</div>

注意事项: 运动的对象就是你ID  为wrapper下的第一个子元素。只有wrapper里的第一个子元素才可以滚动,如果你想要更多的元素可以滚动,那么你可以试试下面的这种写法:

<div id="wrapper"> 
    <div id="scroller">
        <ul> <li></li> ... </ul> 
        <ul> <li></li> ... </ul>
    </div>
</div>

2.3、实现iScroll插件的onScrollEnd事件, 也就是在这个事件里调用你自己的ajax方法实现数据的刷新和追加。

onScrollEnd: function () {
      if (pullDownEl.className.match(\'flip\')) {
                console.log(12);
                pullDownEl.className = \'loading\';
                pullDownEl.querySelector(\'.pullDownLabel\').innerHTML = \'加载中...\';                
                pullDownAction();    // Execute custom function (ajax call?)
       } else if (pullUpEl.className.match(\'flip\')) {
                console.log(13);
                pullUpEl.className = \'loading\';
                pullUpEl.querySelector(\'.pullUpLabel\').innerHTML = \'加载中...\';                
                pullUpAction();    // Execute custom function (ajax call?)
      }
}

  2.4、上拉加载更多请求后台时就相当于分页请求数据,这时候需要在ajax请求时发送pageIndex参数,而初始化加载时需要从后台返回一个pageCount以便前台判断。

  2.5、最关键的就是实现下拉刷新方法(pullDownAction)和上拉加载更多(pullUpAction)方法。

 

3、效果图:

4、代码分析【index.js】

var myScroll,
    pullDownEl, pullDownOffset,
    pullUpEl, pullUpOffset,
    generatedCount = 0;

//pullDownAction方法用于模拟下拉刷新成功后,向顶端追加数据;
function pullDownAction () {
    setTimeout(function () {    
        var el, li, i;
        el = document.getElementById(\'thelist\');

        for (i=0; i<3; i++) {
            console.log("generatedCount:"+generatedCount);
            li = document.createElement(\'li\');
            li.innerText = \'Generated row \' + (++generatedCount);
            el.insertBefore(li, el.childNodes[0]);
        }
        myScroll.refresh();        //数据加载完成后,调用界面更新方法 
    }, 1000);    // <-- Simulate network congestion, remove setTimeout from production!
}

//pullDownAction方法用于模拟上拉刷新成功后,向底端追加数据;
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.innerText = \'Generated row \' + (++generatedCount);
            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!
}

/*初始化iScroll控件*/
function loaded() {
    pullDownEl = document.getElementById(\'pullDown\');
    pullDownOffset = pullDownEl.offsetHeight;//表示获取元素自身的高度
    pullUpEl = document.getElementById(\'pullUp\');    
    pullUpOffset = pullUpEl.offsetHeight;
    
    myScroll = new iScroll(\'wrapper\', {
        useTransition: true,   //表示是否使用css3中的过渡效果,默认为true;
        topOffset: pullDownOffset,//pullDown区间高度
        hScrollbar:false, //false隐藏水平方向上的滚动条
        vScrollbar:false// false 隐藏垂直方向上的滚动条
        onRefresh: function () {  //刷新方法
            if (pullDownEl.className.match(\'loading\')) {
                console.log(19);
                pullDownEl.className = \'\';
                pullDownEl.querySelector(\'.pullDownLabel\').innerHTML = \'下拉刷新...\';
            } else if (pullUpEl.className.match(\'loading\')) {
                console.log(18);
                pullUpEl.className = \'\';
                pullUpEl.querySelector(\'.pullUpLabel\').innerHTML = \'上拉加载更多...\';
            }
        },
        //onScrollMove:主要表示根据用户下拉或上拉刷新的高度值,来显示不同的交互文字;
        onScrollMove: function () {  //手指触摸事件
            //this.y:表示手指下拉的高度
            if (this.y > 5 && !pullDownEl.className.match(\'flip\')) {
                console.log(14);
                pullDownEl.className = \'flip\';
                pullDownEl.querySelector(\'.pullDownLabel\').innerHTML = \'松手开始更新...\';
                this.minScrollY = 0;
            } else if (this.y < 5 && pullDownEl.className.match(\'flip\')) {
                console.log(15);
                pullDownEl.className = \'\';
                pullDownEl.querySelector(\'.pullDownLabel\').innerHTML = \'下拉刷新...\';
                this.minScrollY = -pullDownOffset;
            } else if (this.y < (this.maxScrollY - 5) && !pullUpEl.className.match(\'flip\')) {
                console.log(16);
                pullUpEl.className = \'flip\';
                pullUpEl.querySelector(\'.pullUpLabel\').innerHTML = \'松手开始更新...\';
                this.maxScrollY = this.maxScrollY;
            } else if (this.y > (this.maxScrollY + 5) && pullUpEl.className.match(\'flip\')) {
                console.log(17);
                pullUpEl.className = \'\';
                pullUpEl.querySelector(\'.pullUpLabel\').innerHTML = \'上拉加载更多...\';
                this.maxScrollY = pullUpOffset;
            }
        },
        //onScrollEnd:表示用户下拉刷新完,放开手指时所显示的不同的交互文字
        onScrollEnd: function () {
            if (pullDownEl.className.match(\'flip\')) {
                console.log(12);
                pullDownEl.className = \'loading\';
                pullDownEl.querySelector(\'.pullDownLabel\').innerHTML = \'加载中...\';                
                pullDownAction();    // Execute custom function (ajax call?)
            } else if (pullUpEl.className.match(\'flip\')) {
                console.log(13);
                pullUpEl.className = \'loading\';
                pullUpEl.querySelector(\'.pullUpLabel\').innerHTML = \'加载中...\';                
                pullUpAction();    // Execute custom function (ajax call?)
            }
        }
    });
    
    setTimeout(function () { document.getElementById(\'wrapper\').style.left = \'0\'; }, 800);
}
/*
  touchmove:表示手指在屏幕上滑动连续触发的事件
*/
document.addEventListener(\'touchmove\', function (e) { e.preventDefault(); }, false);
/*
  load事件:仅在所有资源都完全加载后才被触发
  DOMContentLoaded:DOM加载之后及资源加载之前被触发.
*/    
document.addEventListener(\'DOMContentLoaded\', function () { setTimeout(loaded, 200); }, false);
View Code
5、对iScroll进行实例化的几种方法:
  5.1、使用onDOMContentLoaded事件实现滚动(本文使用的就是这种)
         适用于滚动内容只包含文字、图片,并且所有的图片都有固定的尺寸
    注意:myscroll这个变量是全局的,因此你可以在任何地方调用它
 <script>
  var myscroll;
  function loaded(){
      myscroll=new iScroll("wrapper"); 
  } 
  window.addEventListener("DOMContentLoaded",loaded,false); 
</script>

      5.2、使用onLoad事件实现滚动

       因为DOMContentLoaded事件是载入DOM结构后就会被调用,所以在图片等元素未载入前可能无法确定滚动区域的长宽,此时可以使用onLoad事件来实现。

<script> 
var myscroll; 
function loaded(){
     setTimeout(
            function(){ 
            myscroll=new iScroll("wrapper"); },100 );
     }
     window.addEventListener("load",loaded,false); 
</script>

这种情况下iScroll会在页面资源(包括图片)加载完毕100ms之后得到初始化,这应该是一种比较安全的调用iScroll的方式。

  5.3、inline初始化

    这种情况会在页面加载到js的时候就进行调用,此方法不推荐使用。

<script src="iscroll.js"></script>
        <div id="wrapper">
                   <ul>
                         <li></li>
                           ...
                  </ul>
        </div>
<script>
       var myscroll=new iScroll("wrapper");
</script>

  如果你需要使用的话,可以建议你使用一些框架的ready方法来安全调用iScroll(比如jquery里的ready())。

6、 iScroll里传递的参数

  iScroll里的第二个参数允许你自定义一些内容,比如下面的这段代码:

<script>
       var myscroll=new iScroll("wrapper",{
      hScrollbar:false,
      vScrollbar:false}
    );
</script>

        第二个参数通常都是一个对象,像上面的这个例子里就设定了不显示滚动条。常用的参数如下:
               hScroll                 false 禁止横向滚动 true横向滚动 默认为true
               vScroll                 false 精致垂直滚动 true垂直滚动 默认为true
               hScrollbar            false隐藏水平方向上的滚动条
               vScrollbar            false 隐藏垂直方向上的滚动条
               fixedScrollbar      在iOS系统上,当元素拖动超出了scroller的边界时,滚动条会收缩,设置为true可以禁止滚动条超出
                                        scroller的可见区域。默认在Android上为true, iOS上为false
               fadeScrollbar     false 指定在无渐隐效果时隐藏滚动条
               hideScrollbar     在没有用户交互时隐藏滚动条 默认为true
               bounce             启用或禁用边界的反弹,默认为true
               momentum       启用或禁用惯性,默认为true,此参数在你想要保存资源的时候非常有用
               lockDirection       false取消拖动方向的锁定, true拖动只能在一个方向上(up/down 或者left/right)

7、各种效果的实现

  7.1、滚动刷新  ‘Pull to refresh’ demo

     你只需要做的就是自定义pullDownAction()这个方法。你可能需要一个ajax来加载新的内容,不过一旦DOM树发生了变化要记得调用refresh这个方法来。

     需要记住的是在例子中我们加了1秒的延迟来模拟网络的延迟效果。 

     7.2、缩放(pinch / zoom)

  只需要设置放大的参数zoom 为true即可实现利用手势来放大和缩小。双击放大和缩小的功能在iScroll 4里也是得到支持的。配置如下:

var myScroll =new iScroll("wrapper",{zoom:true});

    7.3、捕捉元素(snap and snap to element)  ‘Carousel’ demo

  SNAP功能是判断元素是否滑动到指定位置。通过这个效果可以制作花哨的跑马灯效果。

  插件会自动分析滚动区域内相同标签或相同大小的元素做为捕捉对象,也可以通过参数指定捕捉的对象。

var myscroll=new iScroll("wrapper",{
      snap:true,
      momentum:false,
      hScrollbar:false,
      vScrollbar: false
});

    可以通过设置snap参数为指定标签来设定捕捉对象。比如捕捉li标签。  

var myscroll=new iScroll("wrapper",{
      snap:"li",
      momentum:false,
      hScrollbar:false,
      vScrollbar:false
});

在这个例子中scroller可以捕捉到滚动区域中最左上角的li元素 。

     7.4、自定义滚动条(custom scrollbars)

         在iScroll 4这个版本中,可以利用一系列的css来自定义滚动条的呈现。可以给滚动条添加一个class参数,如下:

var myscroll=new iScroll("wrapper",{
  scrollbarClass: "myScrollbar"
});

    需要提醒的是,滚动条是由两个元素组合而成的:容器和显示器。容器同wrapper的高度相同,而显示器则代表的是滚动条本身。
           滚动条的HTML结构如下: 

<div class="myScrollbarV">
           <div></div>
</div>
      .myscrollbarV{
              position:absolute;z-index:100;width:8px;bottom:7px;top:2px;right:1px;
       }
       .myScrollbarV > div {
            position:absolute;
            z-index:100;
            width:100%;
            /* The following is probably what you want to customize */
           background:-webkit-gradient(linear, 0 0, 100% 0, from(#f00), to(#900));
             border:1px solid #800;
            -webkit-background-clip:padding-box;
            -webkit-box-sizing:border-box;
            -webkit-border-radius:4px;
            -webkit-box-shadow:inset 1px 1px 0 rgba(255,255,255,0.5);
         }
View Code

8、通用方法:

     (1)refresh:在DOM树发生变化时,应该调用此方法

      eg: setTimeout(function () { myScroll.refresh(); }, 0); 

     (2)iScroll还提供了scrollTo, scrollToElement和scrollToPage三个方法让你能够通过javascript来控制滚动效果。

    scrollTo(x, y, time, relative):在指定的time时间内让内容滚动条x/y的位置。如myScroll.scrollTo(0, -100, 200) 在200毫秒内Y轴向下滚动100像素。myScroll.scrollTo(0, 10, 200, true)可以实现相对当前位置在200毫秒内Y轴向上滚动10像素的效果。

    scrollToElement(element, time):在指定的时间内滚动到指定的元素。如myScroll.scrollToElement(‘li:nth-child(10)’, 100) 在100毫秒内滚动到第10个li元素的位置。第1个参数可以用CSS3中的选择器来筛选元素。

    snapToPage(pageX, pageY, time):在200毫秒内从第1页滚动到第2页(0代表第1页,1代表第2页)。这个使用SNAP功能的时候可以调用这个函数。

   (3)detroy():完全消除myscroll及其占用的内存空间
                eg: myscroll.destroy();

        myScroll = null;

9、iScroll的发展方向

  • 表单域的支持
  • 缩放的优化
  • 更好的桌面浏览器的兼容性
  • onScrol事件的优化
  • 加个哈希值的变化
  • DOM改变后自动刷新