移动端翻页插件dropload.js(支持Zepto和jQuery)

一. 声明

  代码来源:github上的dropload项目。

二. 问题

  dropload.js提供了最基本的上拉翻页,下拉刷新功能。对于由服务端一次返回所有数据的情况基本通用。

  但是,需求往往不是服务端一次性返回所有数据,往往还要支持服务端分页,搜索,排序,多条件筛选等功能。(比较类似美团美食的界面)

三. 解决方案。

  改进1:由于有分页,搜索,排序,多条件筛选功能,可能都不需要上拉,进到页面就没有数据。

  例如:搜索一个服务端不存在的名字。

  所以,添加接口设置setHasData。

MyDropLoad.prototype.setHasData = function(ishasData) {
    var me = this;
    if (ishasData) {
      me.isData = true;
      me.$domDown.html(me.opts.domDown.domRefresh);
      fnRecoverContentHeight(me);
    } else {
      me.isData = false;
      me.$domDown.html(me.opts.domDown.domNoData);
      fnRecoverContentHeight(me);
    }
  };

  改进2:由以上问题还引发了一个bug,选择不同的筛选条件,然后上拉加载更多,此时没有反应了。

  原因较复杂,举例说明:选择不同的筛选条件,数据量不一样,如果不执行resetload,那么页面的的上拉计算距离就存在问题。

    1. 只要发API到服务端,无论返回成功失败,都必须执行resetload,成功时需要在加载完全部新增的数据后resetload。

    2. 更改resetload如下,添加调用计算屏幕尺寸的方法。

MyDropLoad.prototype.resetload = function() {
    var me = this;
    if (me.direction == ‘down‘ && me.upInsertDOM) {
      me.$domUp.css({ ‘height‘: ‘0‘ }).on(‘webkitTransitionEnd mozTransitionEnd transitionend‘, function() {
        me.loading = false;
        me.upInsertDOM = false;
        $(this).remove();
        fnRecoverContentHeight(me);
      });
    } else if (me.direction == ‘up‘) {
      me.loading = false;
      if (me.isData) {
        me.$domDown.html(me.opts.domDown.domRefresh);
        fnRecoverContentHeight(me);
      } else {
        me.$domDown.html(me.opts.domDown.domNoData);
      }
    }
  }

  3. 解决以上两个问题,基本解决了90%的问题,还有一个是setHasData(false)之后的处理。(假设每页的count时20条)

  bug: 在筛序条件1:返回20条数据,上拉加载更多返回10条数据,此时设置setHasData(false)。选择筛选条件2,返回20条数据,上拉加载,你会惊奇的发现拉不动了。

  why: setHasData(false)之后状态还停留在没有更多数据的状态。此时应该锁定了上拉加载,更改筛选条件后,没有解除锁定,所以不能上拉加载了。

解决方法:每次更改搜索条件,筛选条件,排序等时,都需要设置setHasData(true)。

四. 全部代码

;
(function($) {
  ‘use strict‘;
  var win = window;
  var doc = document;
  var $win = $(win);
  var $doc = $(doc);
  $.fn.dropload = function(options) {
    return new MyDropLoad(this, options);
  };
  var MyDropLoad = function(element, options) {
    var me = this;
    me.$element = $(element);
    me.upInsertDOM = false;
    me.loading = false;
    me.isLockUp = false;
    me.isLockDown = false;
    me.isData = true;
    me._scrollTop = 0;
    me.init(options);
  };
  MyDropLoad.prototype.init = function(options) {
    var me = this;
    me.opts = $.extend({}, {
      scrollArea: me.$element,
      domUp: {
        domClass: ‘dropload-up‘,
        domRefresh: ‘<div class="dropload-refresh"><img class="drop-down-icon" src="../images/dropload_down.png"><span>下拉刷新</span></div>‘,
        domUpdate: ‘<div class="dropload-update"><img class="drop-up-icon" src="../images/dropload_up.png"><span>释放更新</span></div>‘,
        domLoad: ‘<div class="dropload-load"><img class="loading-icon" src="../images/droploading.gif"></div>‘
      },
      domDown: {
        domClass: ‘dropload-down‘,
        domRefresh: ‘<div class="dropload-refresh"><img class="drop-up-icon" src="../images/dropload_up.png"><span>上拉加载更多</span></div>‘,
        domLoad: ‘<div class="dropload-load"><img class="loading-icon" src="../images/droploading.gif"></div>‘,
        domNoData: ‘‘
          //domNoData  : ‘<div class="dropload-noData"><span>暂无数据</span></div>‘
      },
      distance: 50, // 拉动距离
      threshold: ‘‘, // 提前加载距离
      loadUpFn: ‘‘, // 上方function
      loadDownFn: ‘‘ // 下方function
    }, options);

    if (me.opts.loadDownFn != ‘‘) {
      me.$element.append(‘<div class="‘ + me.opts.domDown.domClass + ‘">‘ + me.opts.domDown.domRefresh + ‘</div>‘);
      me.$domDown = $(‘.‘ + me.opts.domDown.domClass);
    }

    if (me.opts.scrollArea == win) {
      me.$scrollArea = $win;
      me._scrollContentHeight = $doc.height();
      me._scrollWindowHeight = doc.documentElement.clientHeight;
    } else {
      me.$scrollArea = me.opts.scrollArea;
      me._scrollContentHeight = me.$element[0].scrollHeight;
      me._scrollWindowHeight = me.$element.height();
    }

    $win.on(‘resize‘, function() {
      if (me.opts.scrollArea == win) {
        me._scrollWindowHeight = win.innerHeight;
      } else {
        me._scrollWindowHeight = me.$element.height();
      }
    });

    me.$element.on(‘touchstart‘, function(e) {
      if (!me.loading) {
        fnTouches(e);
        fnTouchstart(e, me);
      }
    });
    me.$element.on(‘touchmove‘, function(e) {
      if (!me.loading) {
        fnTouches(e, me);
        fnTouchmove(e, me);
      }
    });
    me.$element.on(‘touchend‘, function() {
      if (!me.loading) {
        fnTouchend(me);
      }
    });

    me.$scrollArea.on(‘scroll‘, function() {
      me._scrollTop = me.$scrollArea.scrollTop();
      fnRecoverContentHeight(me)
      if (me.opts.threshold === ‘‘) {
        me._threshold = Math.floor(me.$domDown.height() * 1 / 3);
      } else {
        me._threshold = me.opts.threshold;
      }
      if (me.opts.loadDownFn != ‘‘ && !me.loading && !me.isLockDown && me._threshold != 0 && (me._scrollContentHeight - me._threshold) <= (me._scrollWindowHeight + me._scrollTop)) {
        fnLoadDown();
      }
    });

    function fnLoadDown() {
      me.direction = ‘up‘;
      me.$domDown.html(me.opts.domDown.domLoad);
      me.loading = true;
      me.opts.loadDownFn(me);
    }
  };

  function fnTouches(e) {
    if (!e.touches) {
      e.touches = e.originalEvent.touches;
    }
  }

  function fnTouchstart(e, me) {
    me._startY = e.touches[0].pageY;
    me.touchScrollTop = me.$scrollArea.scrollTop();
  }

  function fnTouchmove(e, me) {
    me._curY = e.touches[0].pageY;
    me._moveY = me._curY - me._startY;

    if (me._moveY > 0) {
      me.direction = ‘down‘;
    } else if (me._moveY < 0) {
      me.direction = ‘up‘;
    }

    var _absMoveY = Math.abs(me._moveY);

    if (me.opts.loadUpFn != ‘‘ && me.touchScrollTop <= 0 && me.direction == ‘down‘ && !me.isLockUp) {
      e.preventDefault();

      me.$domUp = $(‘.‘ + me.opts.domUp.domClass);
      if (!me.upInsertDOM) {
        me.$element.prepend(‘<div class="‘ + me.opts.domUp.domClass + ‘"></div>‘);
        me.upInsertDOM = true;
      }
      fnTransition(me.$domUp, 0);
      if (_absMoveY <= me.opts.distance) {
        me._offsetY = _absMoveY;
        me.$domUp.html(me.opts.domUp.domRefresh);
      } else if (_absMoveY > me.opts.distance && _absMoveY <= me.opts.distance * 2) {
        me._offsetY = me.opts.distance + (_absMoveY - me.opts.distance) * 0.5;
        me.$domUp.html(me.opts.domUp.domUpdate);
      } else {
        me._offsetY = me.opts.distance + me.opts.distance * 0.5 + (_absMoveY - me.opts.distance * 2) * 0.2;
      }
      me.$domUp.css({ ‘height‘: me._offsetY });
    }
  }

  // touchend
  function fnTouchend(me) {
    var _absMoveY = Math.abs(me._moveY);
    if (me.opts.loadUpFn != ‘‘ && me.touchScrollTop <= 0 && me.direction == ‘down‘ && !me.isLockUp) {
      fnTransition(me.$domUp, 300);

      if (_absMoveY > me.opts.distance) {
        me.$domUp.css({ ‘height‘: me.$domUp.children().height() });
        me.$domUp.html(me.opts.domUp.domLoad);
        me.loading = true;
        me.opts.loadUpFn(me);
      } else {
        me.$domUp.css({ ‘height‘: ‘0‘ }).on(‘webkitTransitionEnd transitionend‘, function() {
          me.upInsertDOM = false;
          $(this).remove();
        });
      }
      me._moveY = 0;
    }
  }

  // 重新获取文档高度
  function fnRecoverContentHeight(me) {
    if (me.opts.scrollArea == win) {
      me._scrollContentHeight = $doc.height();
    } else {
      me._scrollContentHeight = me.$element[0].scrollHeight;
    }
  }

  MyDropLoad.prototype.lock = function(direction) {
    var me = this;
    if (direction === undefined) {
      if (me.direction == ‘up‘) {
        me.isLockDown = true;
      } else if (me.direction == ‘down‘) {
        me.isLockUp = true;
      } else {
        me.isLockUp = true;
        me.isLockDown = true;
      }
    } else if (direction == ‘up‘) {
      me.isLockUp = true;
    } else if (direction == ‘down‘) {
      me.isLockDown = true;
    }
  };

  MyDropLoad.prototype.unlock = function() {
    var me = this;
    me.isLockUp = false;
    me.isLockDown = false;
  };

  MyDropLoad.prototype.setHasData = function(ishasData) {
    var me = this;
    if (ishasData) {
      me.isData = true;
      me.$domDown.html(me.opts.domDown.domRefresh);
      fnRecoverContentHeight(me);
    } else {
      me.isData = false;
      me.$domDown.html(me.opts.domDown.domNoData);
      fnRecoverContentHeight(me);
    }
  };

  MyDropLoad.prototype.resetload = function() {
    var me = this;
    if (me.direction == ‘down‘ && me.upInsertDOM) {
      me.$domUp.css({ ‘height‘: ‘0‘ }).on(‘webkitTransitionEnd mozTransitionEnd transitionend‘, function() {
        me.loading = false;
        me.upInsertDOM = false;
        $(this).remove();
        fnRecoverContentHeight(me);
      });
    } else if (me.direction == ‘up‘) {
      me.loading = false;
      if (me.isData) {
        me.$domDown.html(me.opts.domDown.domRefresh);
        fnRecoverContentHeight(me);
      } else {
        me.$domDown.html(me.opts.domDown.domNoData);
      }
    }
  };

  function fnTransition(dom, num) {
    dom.css({
      ‘-webkit-transition‘: ‘all ‘ + num + ‘ms‘,
      ‘transition‘: ‘all ‘ + num + ‘ms‘
    });
  }
})(window.Zepto || window.jQuery);
.dropload-up,
.dropload-down {
  background-color: #F0EFF5;
  position: relative;
  height: 0;
  overflow: hidden;
}

.dropload-down {
  height: 50px;
  border-top: 1px solid #e5e5e5;
}

.dropload-refresh .drop-up-icon,
.dropload-refresh .drop-down-icon,
.dropload-update .drop-up-icon,
.dropload-update .drop-down-icon {
  vertical-align: text-bottom;
  margin-right: 3px;
  height: 16px;
  width: 12px;
}

.dropload-load .loading-icon {
  vertical-align: middle;
  height: 20px;
  width: 20px;
}

.dropload-refresh span,
.dropload-update span {
  vertical-align: middle;
  line-height: 18px;
  font-size: 16px;
  color: #585858;
}

.dropload-noData {
  border-bottom: 1px solid #e5e5e5;
  background-color: #FFFFFF;
}

.dropload-noData span {
  line-height: 18px;
  font-size: 14px;
  color: #999999;
}

.dropload-refresh,
.dropload-update,
.dropload-load,
.dropload-noData {
  position: absolute;
  width: 100%;
  height: 50px;
  bottom: 0;
  line-height: 50px;
  text-align: center;
}

.dropload-down .dropload-refresh,
.dropload-down .dropload-update,
.dropload-down .dropload-load {
  top: 0;
  bottom: auto;
}
时间: 2024-10-14 06:39:41

移动端翻页插件dropload.js(支持Zepto和jQuery)的相关文章

移动端日历选择控件(支持Zepto和JQuery)

一. 效果图 二. 说明 目前只支持Zepto,使用JQuery时需要更改部分代码.代码很简单并且都有注释,不做详细介绍. 三. 代码 (function($) { $.fn.mdater = function(config) { var defaults = { maxDate: null, minDate: new Date(1970, 0, 1) }; var option = $.extend(defaults, config); //window.console && conso

jQuery翻页yunm.pager.js,涉及div局部刷新

前端的翻页插件有很多,bootstrap的翻页界面看起来就不错,做起来也易于上手,但应用于项目中的翻页实现还有有几个难点,分别是: 如何封装一个翻页插件,如题中的yunm.pager.js. 涉及到的div局部刷新该如何做. 翻页的总体流程涉及到的知识点很多,这篇文章我们也主要来关注以上两点,其余的内容,请自悟. 一.如何定义局部刷新的div 翻页时,我们一般只会刷新页面中涉及到翻页的父级div,那么该如何定义呢? <form rel="support_deal_page" ta

使用jQuery.fn自定义jQuery翻页插件

第一次写jQuery插件.自己感觉写的也不怎么样.写jQuery插件利用的就是这个东东 jQuery.fn,例如 jQuery.fn.pluginName=function(){}; 这个是我写的分页插件的样子 插件通过一个外放的函数来进行翻页操作,无论是点击前进.后退.还是改变页面大小,都会调用该函数. 先看看插件的代码结构 (function ($) { //存放插件所需的属性字段 var PagerFields = { }; //插件的私有函数 function setImageButto

移动端下拉分页加载插件dropload.js

一.dropload.js下载地址: http://www.jq22.com/jquery-info6960 该地址有dropload.js的基础说明文档,下载的压缩包有相应的demo 二.依赖 Zepto 或者 jQuery 1.7以上版本,推荐jQuery 2.x版本(二者不要同时引用) Zepto or jQuery 1.7+,recommend to use jQuery 2.x(not use them at the same time) 三.bug及解决方案 1.小屏手机不加载问题

移动端触摸滑动插件swipe.js

插件特色 swipe.js是一个比较有名的触摸滑动插件,它能够处理内容滑动,支持自定义选项,你可以让它自动滚动,控制滚动间隔,返回回调函数等.经常可见使用在移动前端开发中. 使用方法 下面是一个比较简单的使用例子,添加适当的HTML代码和js代码即可. <div id='slider' class='swipe'> <div class='swipe-wrap'> <div></div> <div></div> <div>

移动端轮播图插件(支持Zepto和jQuery)

一. 效果图 二. 简单介绍 代码都有注释,逻辑简单,不做更多赘述. /* * slider */ ; (function($) { $.extend($.fn, { slider: function(obj) { this.each(function() { // 当前Zepto对象 var $self = $(this); var dom = { "wrap": $self.find(".slider-list"), "item": $sel

jQuery和CSS3全屏垂直翻页特效插件

FSVS(Full Screen Vertical Scroller)是一款jQuery和CSS3带过渡效果的全屏垂直翻页特效插件.该全屏翻页插件在页面上下滚动时一次翻一屏,并带有CSS3过渡动画效果. 该jquery翻页插件的效果和OnePageScroll.js类似,但使用上要简单得多. 在线演示:http://www.htmleaf.com/Demo/201503021447.html 下载地址:http://www.htmleaf.com/jQuery/Layout-Interface/

jQuery支持mobile的全屏水平横向翻页效果

这是一款支持移动手机mobile设备的jQuery全屏水平横向翻页效果插件.该翻页插件可以使页面在水平方向上左右全屏翻动,它支持手机触摸屏,支持使用鼠标滚动页面. 整个页面过渡平滑,效果非常不错. 在线演示:http://www.htmleaf.com/Demo/201503141519.html 下载地址:http://www.htmleaf.com/jQuery/Layout-Interface/201503141518.html

turn.js (翻页效果)总结

Turn.js是一个内置的jQuery翻页插件 1 html中引入<script type="text/javascript" src="js/turn.js"></script> 2  创建html <div id="flipbook"> <div class="hard"> Turn.js </div> <div class="hard"