iScroll横向滚动区域无法拉动页面的解决方案

近期项目中使用iScroll遇到一个问题,在设定scroll-box为横向滚动时,如果你手指放在该区域,将无法拉动页面,也就是说该区域取消了默认事件。这个体验是实在是无法接受,这样子照成无法拉动页面,查看滚动区域下面的内容。

Google了一下子,有个高手给出了解决方案,参考地址:http://stackoverflow.com/questions/7800261/iscroll-with-native-scrolling-on-one-axis

思路如下:

我们知道正常调用触摸事件scroll是这样子的  new iScroll("scroll-box",{hScrollbar:false,vScrollbar:false,vScroll:false};

通过分析iScroll源码发现 再拖动区域触发 touchstart 或者 mousedown事件的时候会首先调用 _start(e);

源码流程:

//事件触发
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};的时候 首页会调用

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();
}
}

}

 

到这里的时候感觉就不错了。但是不要高兴的太早。

上下滑动横向滚动区域,页面确实可以滚动了,但在多体验了几次页面之后,又出现了一个问题。

先左右滑动该区域,滚动停止后再按住该区域想滚动页面,你会发现它还是不能滚动页面,这时你再点击一次该区域,这时可以了。这相对于你需要触摸2次才能滚动页面, 这样的行为还是让人无法接受。

经过多翻测试,我把问题锁定到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 搞定了! 

 

posted @ 2013-11-01 14:43  qgd87  阅读(2906)  评论(1编辑  收藏  举报