移動(dòng)端翻頁(yè)插件dropload.js(支持Zepto和jQuery)
dropload.js提供了最基本的上拉翻頁(yè),下拉刷新功能。對(duì)于由服務(wù)端一次返回所有數(shù)據(jù)的情況基本通用。
但是,需求往往不是服務(wù)端一次性返回所有數(shù)據(jù),往往還要支持服務(wù)端分頁(yè),搜索,排序,多條件篩選等功能。(比較類(lèi)似美團(tuán)美食的界面)
一、解決方案
改進(jìn)1:由于有分頁(yè),搜索,排序,多條件篩選功能,可能都不需要上拉,進(jìn)到頁(yè)面就沒(méi)有數(shù)據(jù)。
例如:搜索一個(gè)服務(wù)端不存在的名字。
所以,添加接口設(shè)置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);
}
};
改進(jìn)2:由以上問(wèn)題還引發(fā)了一個(gè)bug,選擇不同的篩選條件,然后上拉加載更多,此時(shí)沒(méi)有反應(yīng)了。
原因較復(fù)雜,舉例說(shuō)明:選擇不同的篩選條件,數(shù)據(jù)量不一樣,如果不執(zhí)行resetload,那么頁(yè)面的的上拉計(jì)算距離就存在問(wèn)題。
1. 只要發(fā)API到服務(wù)端,無(wú)論返回成功失敗,都必須執(zhí)行resetload,成功時(shí)需要在加載完全部新增的數(shù)據(jù)后resetload。
2. 更改resetload如下,添加調(diào)用計(jì)算屏幕尺寸的方法。
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. 解決以上兩個(gè)問(wèn)題,基本解決了90%的問(wèn)題,還有一個(gè)是setHasData(false)之后的處理。(假設(shè)每頁(yè)的count時(shí)20條)
bug: 在篩序條件1:返回20條數(shù)據(jù),上拉加載更多返回10條數(shù)據(jù),此時(shí)設(shè)置setHasData(false)。選擇篩選條件2,返回20條數(shù)據(jù),上拉加載,你會(huì)驚奇的發(fā)現(xiàn)拉不動(dòng)了。
why: setHasData(false)之后狀態(tài)還停留在沒(méi)有更多數(shù)據(jù)的狀態(tài)。此時(shí)應(yīng)該鎖定了上拉加載,更改篩選條件后,沒(méi)有解除鎖定,所以不能上拉加載了。
解決方法:每次更改搜索條件,篩選條件,排序等時(shí),都需要設(shè)置setHasData(true)。
二、調(diào)用方法
整體頁(yè)面邏輯較復(fù)雜。這里在整體解釋一遍。
1. 選擇要上拉加載的DIV,添加調(diào)用方法。
注意事項(xiàng):
(1)記得保存返回對(duì)象。
(2)LoadDownFn時(shí)上拉加載后的回調(diào),這里自己要處理的邏輯。我這里時(shí)翻頁(yè)發(fā)API,API參數(shù)中offset加20,然后發(fā)API。
(3)無(wú)論API返回失敗成功,都必須resetload。
這里強(qiáng)調(diào):
fetchData函數(shù)調(diào)用發(fā)API,失敗或者成功都必須self.moreFund.resetload()。
并且失敗時(shí)直接調(diào)用self.moreFund.resetload()即可。成功時(shí)要在新的數(shù)據(jù)返回后,要先用JS動(dòng)態(tài)加載HTML,加載完成后在執(zhí)行self.moreFund.resetload()。
self.moreFund = $('#table-fundlist').dropload({
scrollArea: window,
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: ''
},
loadDownFn: function() {
self.apiParams.offset += 20;
self.fetchData(true);
}
});
2. setHasData詳解
(1)什么時(shí)候需要設(shè)置true。
當(dāng)非翻頁(yè)API觸發(fā)之前。即選擇新的篩選條件,選擇新的搜索字段,選擇新的排序字段。這個(gè)時(shí)候必須setHasData(true)。
this.moreFund.setHasData(true);
(2)什么時(shí)候設(shè)置false。
服務(wù)端返回?cái)?shù)據(jù)后,比較服務(wù)端返回的條目數(shù)與API發(fā)送的條目數(shù)是否一致,不一致設(shè)置setHasData(false)。
if (data.length < this.apiParams.count){
this.moreFund.setHasData(false);
this.moreFund.lock();
}
3. lock與unlock詳解
(1)什么時(shí)候設(shè)置lock。
服務(wù)端返回?cái)?shù)據(jù)后,比較服務(wù)端返回的條目數(shù)與API發(fā)送的條目數(shù)是否一致,不一致設(shè)置lock()。
當(dāng)前頁(yè)面狀態(tài)不需要上拉加載時(shí)需要設(shè)置lock()。例如:在搜索框輸入的狀態(tài)。
(2)什么時(shí)候設(shè)置unlock。
只有一個(gè)地方需要調(diào)用。發(fā)送API之前設(shè)置unlock。
if (self.moreFund) {
self.moreFund.unlock();
}
三、JS和CSS源代碼
js:
(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>暫無(wú)數(shù)據(jù)</span></div>'
},
distance: 50, // 拉動(dòng)距離
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);
CSS:
.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;
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- jsp實(shí)現(xiàn)上一頁(yè)下一頁(yè)翻頁(yè)功能(示例代碼)
- JavaScript中transform實(shí)現(xiàn)數(shù)字翻頁(yè)效果
- JavaScript實(shí)現(xiàn)翻頁(yè)功能(附效果圖)
- 基于Vuejs框架實(shí)現(xiàn)翻頁(yè)組件
- Js實(shí)現(xiàn)網(wǎng)頁(yè)鍵盤(pán)控制翻頁(yè)的方法
- js實(shí)現(xiàn)翻頁(yè)后保持checkbox選中狀態(tài)的實(shí)現(xiàn)方法
- 一個(gè)JS翻頁(yè)效果
- javascript移動(dòng)端 電子書(shū) 翻頁(yè)效果實(shí)現(xiàn)代碼
相關(guān)文章
詳解 javascript對(duì)象創(chuàng)建模式
這篇文章主要介紹了詳解 javascript對(duì)象創(chuàng)建模式的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)JavaScript的相關(guān)知識(shí)。感興趣的朋友可以了解下2020-10-10
用js實(shí)現(xiàn)放大鏡的效果的簡(jiǎn)單實(shí)例
下面小編就為大家?guī)?lái)一篇用js實(shí)現(xiàn)放大鏡的效果的簡(jiǎn)單實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-05-05
基于JS實(shí)現(xiàn)無(wú)縫滾動(dòng)思路及代碼分享
無(wú)縫滾動(dòng)效果在各大網(wǎng)站都有這樣的需求,應(yīng)用非常廣泛,下面小編給大家分享基于JS實(shí)現(xiàn)無(wú)縫滾動(dòng)思路及代碼,非常不錯(cuò)具有參考借鑒價(jià)值,感興趣的朋友一起看下吧2016-06-06
學(xué)習(xí)JavaScript編程語(yǔ)言的8張思維導(dǎo)圖分享
這篇文章主要介紹了學(xué)習(xí)JavaScript編程語(yǔ)言的8張思維導(dǎo)圖分享,本文給出了javascript變量、javascript運(yùn)算符、javascript數(shù)組、javascript流程語(yǔ)句、javascript字符串函數(shù)、javascript函數(shù)基礎(chǔ)、javascript基礎(chǔ)DOM操作、javascript正則表達(dá)式的思維導(dǎo)圖,需要的可以參考下2015-03-03
layui當(dāng)點(diǎn)擊文本框時(shí)彈出選擇框,顯示選擇內(nèi)容的例子
今天小編就為大家分享一篇layui當(dāng)點(diǎn)擊文本框時(shí)彈出選擇框,顯示選擇內(nèi)容的例子,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-09-09
用JavaScript事件串連執(zhí)行多個(gè)處理過(guò)程的方法
用JavaScript事件串連執(zhí)行多個(gè)處理過(guò)程的方法...2007-03-03

