移动端翻页插件dropload.js(支持Zepto和jQuery)
dropload.js提供了最基本的上拉翻页,下拉刷新功能。对于由服务端一次返回所有数据的情况基本通用。
但是,需求往往不是服务端一次性返回所有数据,往往还要支持服务端分页,搜索,排序,多条件筛选等功能。(比较类似美团美食的界面)
一、解决方案
改进1:由于有分页,搜索,排序,多条件筛选功能,可能都不需要上拉,进到页面就没有数据。
例如:搜索一个服务端不存在的名字。
所以,添加接口设置setHasData。
MyDropLoad.prototype.setHasData=function(ishasData){
varme=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(){
varme=this;
if(me.direction=='down'&&me.upInsertDOM){
me.$domUp.css({'height':'0'}).on('webkitTransitionEndmozTransitionEndtransitionend',function(){
me.loading=false;
me.upInsertDOM=false;
$(this).remove();
fnRecoverContentHeight(me);
});
}elseif(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)。
二、调用方法
整体页面逻辑较复杂。这里在整体解释一遍。
1.选择要上拉加载的DIV,添加调用方法。
注意事项:
(1)记得保存返回对象。
(2)LoadDownFn时上拉加载后的回调,这里自己要处理的逻辑。我这里时翻页发API,API参数中offset加20,然后发API。
(3)无论API返回失败成功,都必须resetload。
这里强调:
fetchData函数调用发API,失败或者成功都必须self.moreFund.resetload()。
并且失败时直接调用self.moreFund.resetload()即可。成功时要在新的数据返回后,要先用JS动态加载HTML,加载完成后在执行self.moreFund.resetload()。
self.moreFund=$('#table-fundlist').dropload({
scrollArea:window,
domDown:{
domClass:'dropload-down',
domRefresh:'<divclass="dropload-refresh"><imgclass="drop-up-icon"src="images/dropload_up.png"><span>上拉加载更多</span></div>',
domLoad:'<divclass="dropload-load"><imgclass="loading-icon"src="images/droploading.gif"></div>',
domNoData:''
},
loadDownFn:function(){
self.apiParams.offset+=20;
self.fetchData(true);
}
});
2.setHasData详解
(1)什么时候需要设置true。
当非翻页API触发之前。即选择新的筛选条件,选择新的搜索字段,选择新的排序字段。这个时候必须setHasData(true)。
this.moreFund.setHasData(true);
(2)什么时候设置false。
服务端返回数据后,比较服务端返回的条目数与API发送的条目数是否一致,不一致设置setHasData(false)。
if(data.length<this.apiParams.count){
this.moreFund.setHasData(false);
this.moreFund.lock();
}
3.lock与unlock详解
(1)什么时候设置lock。
服务端返回数据后,比较服务端返回的条目数与API发送的条目数是否一致,不一致设置lock()。
当前页面状态不需要上拉加载时需要设置lock()。例如:在搜索框输入的状态。
(2)什么时候设置unlock。
只有一个地方需要调用。发送API之前设置unlock。
if(self.moreFund){
self.moreFund.unlock();
}
三、JS和CSS源代码
js:
(function($){
'usestrict';
varwin=window;
vardoc=document;
var$win=$(win);
var$doc=$(doc);
$.fn.dropload=function(options){
returnnewMyDropLoad(this,options);
};
varMyDropLoad=function(element,options){
varme=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){
varme=this;
me.opts=$.extend({},{
scrollArea:me.$element,
domUp:{
domClass:'dropload-up',
domRefresh:'<divclass="dropload-refresh"><imgclass="drop-down-icon"src="../images/dropload_down.png"><span>下拉刷新</span></div>',
domUpdate:'<divclass="dropload-update"><imgclass="drop-up-icon"src="../images/dropload_up.png"><span>释放更新</span></div>',
domLoad:'<divclass="dropload-load"><imgclass="loading-icon"src="../images/droploading.gif"></div>'
},
domDown:{
domClass:'dropload-down',
domRefresh:'<divclass="dropload-refresh"><imgclass="drop-up-icon"src="../images/dropload_up.png"><span>上拉加载更多</span></div>',
domLoad:'<divclass="dropload-load"><imgclass="loading-icon"src="../images/droploading.gif"></div>',
domNoData:''
//domNoData:'<divclass="dropload-noData"><span>暂无数据</span></div>'
},
distance:50,//拉动距离
threshold:'',//提前加载距离
loadUpFn:'',//上方function
loadDownFn:''//下方function
},options);
if(me.opts.loadDownFn!=''){
me.$element.append('<divclass="'+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();
}
});
functionfnLoadDown(){
me.direction='up';
me.$domDown.html(me.opts.domDown.domLoad);
me.loading=true;
me.opts.loadDownFn(me);
}
};
functionfnTouches(e){
if(!e.touches){
e.touches=e.originalEvent.touches;
}
}
functionfnTouchstart(e,me){
me._startY=e.touches[0].pageY;
me.touchScrollTop=me.$scrollArea.scrollTop();
}
functionfnTouchmove(e,me){
me._curY=e.touches[0].pageY;
me._moveY=me._curY-me._startY;
if(me._moveY>0){
me.direction='down';
}elseif(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('<divclass="'+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);
}elseif(_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
functionfnTouchend(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('webkitTransitionEndtransitionend',function(){
me.upInsertDOM=false;
$(this).remove();
});
}
me._moveY=0;
}
}
//重新获取文档高度
functionfnRecoverContentHeight(me){
if(me.opts.scrollArea==win){
me._scrollContentHeight=$doc.height();
}else{
me._scrollContentHeight=me.$element[0].scrollHeight;
}
}
MyDropLoad.prototype.lock=function(direction){
varme=this;
if(direction===undefined){
if(me.direction=='up'){
me.isLockDown=true;
}elseif(me.direction=='down'){
me.isLockUp=true;
}else{
me.isLockUp=true;
me.isLockDown=true;
}
}elseif(direction=='up'){
me.isLockUp=true;
}elseif(direction=='down'){
me.isLockDown=true;
}
};
MyDropLoad.prototype.unlock=function(){
varme=this;
me.isLockUp=false;
me.isLockDown=false;
};
MyDropLoad.prototype.setHasData=function(ishasData){
varme=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(){
varme=this;
if(me.direction=='down'&&me.upInsertDOM){
me.$domUp.css({'height':'0'}).on('webkitTransitionEndmozTransitionEndtransitionend',function(){
me.loading=false;
me.upInsertDOM=false;
$(this).remove();
fnRecoverContentHeight(me);
});
}elseif(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);
}
}
};
functionfnTransition(dom,num){
dom.css({
'-webkit-transition':'all'+num+'ms',
'transition':'all'+num+'ms'
});
}
})(window.Zepto||window.jQuery);
CSS:
.dropload-up,
.dropload-down{
background-color:#F0EFF5;
position:relative;
height:0;
overflow:hidden;
}
.dropload-down{
height:50px;
border-top:1pxsolid#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-refreshspan,
.dropload-updatespan{
vertical-align:middle;
line-height:18px;
font-size:16px;
color:#585858;
}
.dropload-noData{
border-bottom:1pxsolid#e5e5e5;
background-color:#FFFFFF;
}
.dropload-noDataspan{
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;
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。