IScroll中当内容不足时下拉刷新的示例分析

小编给大家分享一下IScroll中当内容不足时下拉刷新的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

公司主营业务:成都网站设计、做网站、移动网站开发等业务。帮助企业客户真正实现互联网宣传,提高企业的竞争能力。创新互联是一支青春激扬、勤奋敬业、活力青春激扬、勤奋敬业、活力澎湃、和谐高效的团队。公司秉承以“开放、自由、严谨、自律”为核心的企业文化,感谢他们对我们的高要求,感谢他们从不同领域给我们带来的挑战,让我们激情的团队有机会用头脑与智慧不断的给客户带来惊喜。创新互联推出山海关免费做网站回馈大家。

大致的例子是这样的:




 
 
  • item1
  •  
  • item2
  •  
  • item3
  •  
  • item4
  •  
  • item5
  •  

    那么,既然超过一屏是可以刷新的,那我们就来逛逛代码吧。在github上搜索iscroll,打开第一个,找到src下面的core.js。

    1. 思路

    首先既然要下拉,肯定会触发touchstart、touchmove以及touchend事件。搜索touchmove,很好,在_initEvents中的注册了这个事件。

    _initEvents: function (remove) {
     // ...
     // 这里省略若干代码
    
     if ( utils.hasTouch && !this.options.disableTouch ) {
      eventType(this.wrapper, 'touchstart', this);
      eventType(target, 'touchmove', this);
      eventType(target, 'touchcancel', this);
      eventType(target, 'touchend', this);
     }
    
     // ...
    },

    好吧,看到这里的时候,我表示懵了一下逼,这不就是个绑定事件么?this又是一个什么鬼,然后我去查了一下文档,发现了这么一个东西。文档地址

    target.addEventListener(type, listener[, options]);
    target.addEventListener(type, listener[, useCapture]);
    target.addEventListener(type, listener[, useCapture, wantsUntrusted ]); 
    // 
    // Gecko/Mozilla only
    
    listener
    
    当所监听的事件类型触发时,会接收到一个事件通知(实现了 Event 接口的对象)对象。listener 必须是一个实现了 EventListener 接口的对象,或者是一个函数

    木有看错,listener是一个对象或者是一个函数。前提是这个对象实现了EventListener接口。我们接着往下看,发现了这么一个例子。

    var Something = function(element) {
     // |this| is a newly created object
     this.name = 'Something Good';
     this.handleEvent = function(event) {
     console.log(this.name); 
     // 'Something Good', as this is bound to newly created object
     switch(event.type) {
      case 'click':
      // some code here...
      break;
      case 'dblclick':
      // some code here...
      break;
     }
     };
    
     // Note that the listeners in this case are |this|, not this.handleEvent
     element.addEventListener('click', this, false);
     element.addEventListener('dblclick', this, false);
    
     // You can properly remove the listeners
     element.removeEventListener('click', this, false);
     element.removeEventListener('dblclick', this, false);
    }
    var s = new Something(document.body);

    然后在去IScroll的源码去找,发现了同样的实现方式。在default文件夹中有一个handleEvent.js。

    好了,这个梗先告一段落。还是继续看源码。在handleEvent.js中,有这么一段东西。

    handleEvent: function (e) {
     switch ( e.type ) {
      case 'touchstart':
      case 'pointerdown':
      case 'MSPointerDown':
      case 'mousedown':
      this._start(e);
      break;
      case 'touchmove':
      case 'pointermove':
      case 'MSPointerMove':
      case 'mousemove':
      this._move(e);
      break;
      case 'touchend':
      case 'pointerup':
      case 'MSPointerUp':
      case 'mouseup':
      case 'touchcancel':
      case 'pointercancel':
      case 'MSPointerCancel':
      case 'mousecancel':
      this._end(e);
      break;
      // ...
     }
     }
    };

    发现在start/move/end分别调用了内部方法_start/_move/_end方法。去看看这三个方法,看其中可能会引起不会滑动的点。

    在_start方法中,看到这样的几行代码,会不会是直接返回了呢?分析分析:

    if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) {
     return;
    }
    
    // ...
    
    var point = e.touches ? e.touches[0] : e,
     pos;
    
    this.initiated = utils.eventType[e.type];
    this.moved = false;
    initiated属性在最开始肯定是没有的,而enabled默认是true,所以在最开始执行这个方法的时候是不会返回的,而是会给initiated这个属性设置当前的eventType值,这个值会在_move方法中用到。重点来看看_move方法。
    
    if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
     return;
    }

    首先来进行类型判断,因为在_start方法中已经定义了这个值,所以这里也不会返回。接着往下看:

    if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) {
     return;
    }

    【实际上是两次click事件的模拟】如果两次滑动的时间大于了300ms,并且只要一个方向上的位移少于10像素,那么也是会返回的。那么会不会呢,打个断点测试一下就知道了。这里就不贴图了,实际中的测试结果是,每一次移动肯定是在300ms以内的,这里之所以判断300ms,主要是click事件执行会有一个300ms的延迟。而每一次移动,由于手指的触点比较大,还是会大于10像素的,即使两次不大于10像素,也是不影响的。所以这点不会返回。那么继续接着看:

    // If you are scrolling in one direction lock the other
    if ( !this.directionLocked && !this.options.freeScroll ) {
     if ( absDistX > absDistY + this.options.directionLockThreshold ) {
     this.directionLocked = 'h'; // lock horizontally
     } else if ( absDistY >= absDistX + this.options.directionLockThreshold ) {
     this.directionLocked = 'v'; // lock vertically
     } else {
     this.directionLocked = 'n'; // no lock
     }
    }
    
    if ( this.directionLocked == 'h' ) {
     if ( this.options.eventPassthrough == 'vertical' ) {
     e.preventDefault();
     } else if ( this.options.eventPassthrough == 'horizontal' ) {
     this.initiated = false;
     return;
     }
    
     deltaY = 0;
    } else if ( this.directionLocked == 'v' ) {
     if ( this.options.eventPassthrough == 'horizontal' ) {
     e.preventDefault();
     } else if ( this.options.eventPassthrough == 'vertical' ) {
     this.initiated = false;
     return;
     }
    
     deltaX = 0;
    }

    第一个条件判断只要是定义了这次滑动的方向是什么。h表示水平方向,v表示竖直方向。我们是要向下滑动,所以我们关注的是竖直方向。看第二个条件判断,如果是竖直方向,那么将水平方向的deltaX值变为0。这样做的目的是保持绝对的竖直方向。因为移动实际还是根据元素的位移值来的。当probe的版本为2以下的时候,是根据css3的transform属性来移动位移的,为3版本的时候是根据决定对位来移动的。所以这里只要不把我们的deltaY置为0就说明木有什么问题。继续往下看代码:

    deltaX = this.hasHorizontalScroll ? deltaX : 0;
    deltaY = this.hasVerticalScroll ? deltaY : 0;
    
    newX = this.x + deltaX;
    newY = this.y + deltaY;
    // ...
    
    // 这里是移动
    this._translate(newX, newY);

    测试中发现,这个hasVerticalScroll一直是false,那么deltaY一直就是0,也就是移动了也白移动。找到问题原因。那么,这个hasVerticalScroll是从哪里来的?全局找呀找,在refresh中找到这样几行代码:

    this.wrapperWidth = this.wrapper.clientWidth;
    this.wrapperHeight = this.wrapper.clientHeight;
    
    var rect = utils.getRect(this.scroller);
    /* REPLACE START: refresh */
    
    this.scrollerWidth = rect.width;
    this.scrollerHeight = rect.height;
    
    this.maxScrollX = this.wrapperWidth - this.scrollerWidth;
    this.maxScrollY = this.wrapperHeight - this.scrollerHeight;
    
    /* REPLACE END: refresh */
    
    this.hasHorizontalScroll = this.options.scrollX && this.maxScrollX < 0;
    this.hasVerticalScroll = this.options.scrollY && this.maxScrollY < 0;

    refresh方法会在IScroll实例化的时候调用一次。粗略一看,scrollY内置为true,所以只有maxScrollY会大于0。往上看。this.wrapperHeight - this.scrollerHeight肯定是大于0的呀,这就是问题所在。

    那么看看我们最开始代码,这里的wrapperHeight为文档高度,scrollerHeight为内容高度,所以wrapperHeight高度始终大于scrollHeight。但是,手机端页面夹杂的列表,一般都有头部、底部,而中间部分一般都会采用padding的形式来使得列表在全局滚动,这样就不需要每次都要特定地计算列表的高度。

    2. 解决方案

    针对以上问题,只要我们能够使内部的滚动部分高度大于容器高度,那么就能触发滚动。

    2.1 粗略做法

    可以设置一个min-height属性为900px(900只是一个示例,只要够大就可以),这样就可以保证可以滑动。

    2.2 精准做法

    计算当前的容器高度,然后比容器高度多一个像素即可。

    以上是“IScroll中当内容不足时下拉刷新的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注创新互联行业资讯频道!


    文章标题:IScroll中当内容不足时下拉刷新的示例分析
    本文链接:http://hbruida.cn/article/pepedi.html

    其他资讯