近期項目中使用iScroll遇到一個問題,在設定scroll-box爲橫向滾動時,若是你手指放在該區域,將沒法拉動頁面,也就是說該區域取消了默認事件。這個體驗是實在是沒法接受,這樣子照成沒法拉動頁面,查看滾動區域下面的內容。測試
Google了一會兒,有個高手給出瞭解決方案,參考地址:http://stackoverflow.com/questions/7800261/iscroll-with-native-scrolling-on-one-axisthis
思路以下:spa
咱們知道正常調用觸摸事件scroll是這樣子的 new iScroll("scroll-box",{hScrollbar:false,vScrollbar:false,vScroll:false};code
經過分析iScroll源碼發現 再拖動區域觸發 touchstart 或者 mousedown事件的時候會首先調用 _start(e);
blog
源碼流程:事件
//事件觸發 handleEvent: function (e) { var that = this; switch(e.type) { case START_EV: if (!hasTouch && e.button !== 0) return; that._start(e); break; case MOVE_EV: that._move(e); break; case END_EV: case CANCEL_EV: that._end(e); break; case RESIZE_EV: that._resize(); break; case 'DOMMouseScroll': case 'mousewheel': that._wheel(e); break; case TRNEND_EV: that._transitionEnd(e); break; } } //觸發_start(e) _start: function (e) { var that = this, point = hasTouch ? e.touches[0] : e, matrix, x, y, c1, c2; if (!that.enabled) return; if (that.options.onBeforeScrollStart) that.options.onBeforeScrollStart.call(that, e); 。。。。。 //觸發onBeforeScrollStart onBeforeScrollStart: function (e) { e.preventDefault(); },
從代碼中咱們可知 咱們調用new iScroll("scroll-box",{hScrollbar:false,vScrollbar:false,vScroll:false};的時候 首頁會調用get
onBeforeScrollStart : function(){
e.preventDefault();
}
它默認是直接取消默認事件的
所以須要重寫onBeforeScrollStart事件,判斷touch的滑動距離,只在橫向滑動距離大於豎向滑動距離時(也就是左右滑動時)才取消默認事件,這樣就不影響頁面滾動了
代碼以下:
new iScroll("scroll-box",{hScrollbar:false,vScrollbar:false,vScroll:false, onBeforeScrollStart: function ( e ) { if ( this.absDistX > (this.absDistY + 5 ) ) { e.preventDefault(); } } }
到這裏的時候感受就不錯了。可是不要高興的太早。源碼
上下滑動橫向滾動區域,頁面確實能夠滾動了,但在多體驗了幾回頁面以後,又出現了一個問題。it
先左右滑動該區域,滾動中止後再按住該區域想滾動頁面,你會發現它仍是不能滾動頁面,這時你再點擊一次該區域,這時能夠了。這相對於你須要觸摸2次才能滾動頁面, 這樣的行爲仍是讓人沒法接受。io
通過多翻測試,我把問題鎖定到absDistX/Y上。最後發現,在左右滑動以後absDistX/Y的值不會重置,第二次滑動該區域時執行onBeforeScrollStart事件,裏面absDistX/Y值是上一次的值,因此程序仍是阻止了頁面滾動。
代碼以下:
new iScroll("scroll-box",{hScrollbar:false,vScrollbar:false,vScroll:false, onBeforeScrollStart: function ( e ) { if ( this.absDistX > (this.absDistY + 5 ) ) { e.preventDefault(); } }, //解決第一次沒法滑動的問題 onTouchEnd: function () { var self = this; if (self.touchEndTimeId) { clearTimeout(self.touchEndTimeId); } self.touchEndTimeId = setTimeout(function () { self.absDistX = 0; self.absDistY = 0; }, 600); } });
在onTouchEnd裏面作處理,每次滑動以後都重置absDistX/Y的值。
這下OK 搞定了!