近期项目中使用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 搞定了!