IScroll那些事_當(dāng)內(nèi)容不足時(shí)下拉刷新的解決方法
之前項(xiàng)目中的列表是采用的IScroll,但是在使用IScroll有一個(gè)問題就是:當(dāng)內(nèi)容不足全屏的時(shí)候,是木有辦法往下拉的,這樣就達(dá)不到刷新的目的了?!具@是本人工作中遇到的,具體例子具體分析,這里只作一個(gè)參考】
大致的例子是這樣的:
<style> * { margin: 0; padding: 0; } html,body,.container { width: 100%; height: 100%; } .container>ul>li { padding: 15px 20px; text-align: center; border-bottom: 1px solid #ccc; } </style> <div id="container" class="container"> <ul class="scroller"> <li>item1</li> <li>item2</li> <li>item3</li> <li>item4</li> <li>item5</li> </ul> </div> <script src="https://cdn.bootcss.com/iScroll/5.2.0/iscroll.min.js"></script> <script> var myScroll = null; function onLoad() { myScroll = new IScroll('container'); } window.addEventListener('DOMContentLoaded', onLoad, false); </script>
那么,既然超過一屏是可以刷新的,那我們就來逛逛代碼吧。在github上搜索iscroll,打開第一個(gè),找到src下面的core.js。
1. 思路
首先既然要下拉,肯定會(huì)觸發(fā)touchstart、touchmove以及touchend事件。搜索touchmove,很好,在_initEvents中的注冊(cè)了這個(gè)事件。
_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); } // ... },
好吧,看到這里的時(shí)候,我表示懵了一下逼,這不就是個(gè)綁定事件么?this又是一個(gè)什么鬼,然后我去查了一下文檔,發(fā)現(xiàn)了這么一個(gè)東西。文檔地址
target.addEventListener(type, listener[, options]); target.addEventListener(type, listener[, useCapture]); target.addEventListener(type, listener[, useCapture, wantsUntrusted ]); // // Gecko/Mozilla only listener 當(dāng)所監(jiān)聽的事件類型觸發(fā)時(shí),會(huì)接收到一個(gè)事件通知(實(shí)現(xiàn)了 Event 接口的對(duì)象)對(duì)象。listener 必須是一個(gè)實(shí)現(xiàn)了 EventListener 接口的對(duì)象,或者是一個(gè)函數(shù)
木有看錯(cuò),listener是一個(gè)對(duì)象或者是一個(gè)函數(shù)。前提是這個(gè)對(duì)象實(shí)現(xiàn)了EventListener接口。我們接著往下看,發(fā)現(xiàn)了這么一個(gè)例子。
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的源碼去找,發(fā)現(xiàn)了同樣的實(shí)現(xiàn)方式。在default文件夾中有一個(gè)handleEvent.js。
好了,這個(gè)梗先告一段落。還是繼續(xù)看源碼。在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; // ... } } };
發(fā)現(xiàn)在start/move/end分別調(diào)用了內(nèi)部方法_start/_move/_end方法。去看看這三個(gè)方法,看其中可能會(huì)引起不會(huì)滑動(dòng)的點(diǎn)。
在_start方法中,看到這樣的幾行代碼,會(huì)不會(huì)是直接返回了呢?分析分析:
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默認(rèn)是true,所以在最開始執(zhí)行這個(gè)方法的時(shí)候是不會(huì)返回的,而是會(huì)給initiated這個(gè)屬性設(shè)置當(dāng)前的eventType值,這個(gè)值會(huì)在_move方法中用到。重點(diǎn)來看看_move方法。 if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) { return; }
首先來進(jìn)行類型判斷,因?yàn)樵赺start方法中已經(jīng)定義了這個(gè)值,所以這里也不會(huì)返回。接著往下看:
if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) { return; }
【實(shí)際上是兩次click事件的模擬】如果兩次滑動(dòng)的時(shí)間大于了300ms,并且只要一個(gè)方向上的位移少于10像素,那么也是會(huì)返回的。那么會(huì)不會(huì)呢,打個(gè)斷點(diǎn)測(cè)試一下就知道了。這里就不貼圖了,實(shí)際中的測(cè)試結(jié)果是,每一次移動(dòng)肯定是在300ms以內(nèi)的,這里之所以判斷300ms,主要是click事件執(zhí)行會(huì)有一個(gè)300ms的延遲。而每一次移動(dòng),由于手指的觸點(diǎn)比較大,還是會(huì)大于10像素的,即使兩次不大于10像素,也是不影響的。所以這點(diǎn)不會(huì)返回。那么繼續(xù)接著看:
// 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; }
第一個(gè)條件判斷只要是定義了這次滑動(dòng)的方向是什么。h表示水平方向,v表示豎直方向。我們是要向下滑動(dòng),所以我們關(guān)注的是豎直方向。看第二個(gè)條件判斷,如果是豎直方向,那么將水平方向的deltaX值變?yōu)?。這樣做的目的是保持絕對(duì)的豎直方向。因?yàn)橐苿?dòng)實(shí)際還是根據(jù)元素的位移值來的。當(dāng)probe的版本為2以下的時(shí)候,是根據(jù)css3的transform屬性來移動(dòng)位移的,為3版本的時(shí)候是根據(jù)決定對(duì)位來移動(dòng)的。所以這里只要不把我們的deltaY置為0就說明木有什么問題。繼續(xù)往下看代碼:
deltaX = this.hasHorizontalScroll ? deltaX : 0; deltaY = this.hasVerticalScroll ? deltaY : 0; newX = this.x + deltaX; newY = this.y + deltaY; // ... // 這里是移動(dòng) this._translate(newX, newY);
測(cè)試中發(fā)現(xiàn),這個(gè)hasVerticalScroll一直是false,那么deltaY一直就是0,也就是移動(dòng)了也白移動(dòng)。找到問題原因。那么,這個(gè)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方法會(huì)在IScroll實(shí)例化的時(shí)候調(diào)用一次。粗略一看,scrollY內(nèi)置為true,所以只有maxScrollY會(huì)大于0。往上看。this.wrapperHeight - this.scrollerHeight肯定是大于0的呀,這就是問題所在。
那么看看我們最開始代碼,這里的wrapperHeight為文檔高度,scrollerHeight為內(nèi)容高度,所以wrapperHeight高度始終大于scrollHeight。但是,手機(jī)端頁(yè)面夾雜的列表,一般都有頭部、底部,而中間部分一般都會(huì)采用padding的形式來使得列表在全局滾動(dòng),這樣就不需要每次都要特定地計(jì)算列表的高度。
2. 解決方案
針對(duì)以上問題,只要我們能夠使內(nèi)部的滾動(dòng)部分高度大于容器高度,那么就能觸發(fā)滾動(dòng)。
2.1 粗略做法
可以設(shè)置一個(gè)min-height屬性為900px(900只是一個(gè)示例,只要夠大就可以),這樣就可以保證可以滑動(dòng)。
2.2 精準(zhǔn)做法
計(jì)算當(dāng)前的容器高度,然后比容器高度多一個(gè)像素即可。
以上這篇IScroll那些事_當(dāng)內(nèi)容不足時(shí)下拉刷新的解決方法就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- 基于iScroll實(shí)現(xiàn)下拉刷新和上滑加載效果
- H5基于iScroll實(shí)現(xiàn)下拉刷新和上拉加載更多
- iscroll-probe實(shí)現(xiàn)下拉刷新和下拉加載效果
- iOS下拉刷新 UIScrollVie異常閃動(dòng)問題
- 基于iscroll.js實(shí)現(xiàn)下拉刷新和上拉加載效果
- 基于HTML5上使用iScroll實(shí)現(xiàn)下拉刷新,上拉加載更多
- iscroll碰到Select無法選擇下拉刷新的解決辦法
- iscroll.js的上拉下拉刷新時(shí)無法回彈的解決方法
- JQuery插件iScroll實(shí)現(xiàn)下拉刷新,滾動(dòng)翻頁(yè)特效
- iscroll實(shí)現(xiàn)下拉刷新功能
相關(guān)文章
Bootstrap 填充Json數(shù)據(jù)的實(shí)例代碼
本篇文章主要介紹了Bootstrap 填充Json數(shù)據(jù)的實(shí)例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-01-01淺談JavaScript Math和Number對(duì)象
這篇文章主要簡(jiǎn)單介紹了JavaScript Math和Number對(duì)象的相關(guān)資料,需要的朋友可以參考下2015-01-01理解與使用JavaScript中的回調(diào)函數(shù)
這篇文章主要介紹了JavaScript中的回調(diào)函數(shù),想詳細(xì)了解回調(diào)函數(shù)的同學(xué),一定要看一下2021-04-04layui table復(fù)選框禁止某幾條勾選的實(shí)例
今天小編就為大家分享一篇layui table復(fù)選框禁止某幾條勾選的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-09-09普通web整合quartz跑定時(shí)任務(wù)的示例
這篇文章主要介紹了普通web整合quartz跑定時(shí)任務(wù),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03