移動端表層div滑動,致使底層body滑動(touchmove的阻止)

body很長,能夠滑動,body頭部有一個模擬下拉的選擇框,下拉選擇有滾動軸

我給body一個overflow:hidden和高度是沒有用的。手機網站上背景仍是能夠滑動,而後我給body一個touchmove的preventdefault()阻止事件,body滑動阻止了,PC上面是能夠了,可是手機上面滑動div仍是會致使底部body的滑動,我給div 一個阻止冒泡的事件stopPropagation(),手機網站上面仍是不能夠。html

解決方案

我通過反覆測試,發現滾動軸滾到底部的時候,會觸發body的滑動,那麼我就在事件滾到底部的時候對錶層的div作一個touchmove的阻止。到達滾動軸底部,向下滑動,阻止事件,向上滑動,開啓事件。爲此就要判斷touchmove的方向了。瀏覽器

var startX ,startY;
$("body").on("touchstart", function(e) {
    e.preventDefault();
    startX = e.originalEvent.changedTouches[0].pageX,
    startY = e.originalEvent.changedTouches[0].pageY;
});
$("body").on("touchmove", function(e) {
    e.preventDefault();
    var moveEndX = e.originalEvent.changedTouches[0].pageX,
    moveEndY = e.originalEvent.changedTouches[0].pageY,
    X = moveEndX - startX,
    Y = moveEndY - startY;

    if ( Math.abs(X) > Math.abs(Y) && X > 0 ) {
        alert("left 2 right");
    }
    else if ( Math.abs(X) > Math.abs(Y) && X < 0 ) {
        alert("right 2 left");
    }
    else if ( Math.abs(Y) > Math.abs(X) && Y > 0) {
        alert("top 2 bottom");
    }
    else if ( Math.abs(Y) > Math.abs(X) && Y < 0 ) {
        alert("bottom 2 top");
    }
    else{
        alert("just touch");
    }
});

 

上面的方法是判斷touchmove的滑動方向。ide

除了上面方法判斷手機端手機滑動方向,我這裏再介紹一個方案,就是封裝一個角度函數,經過角度函數來判斷也還不錯!我這裏僅僅把這種方式實現上滑下滑左滑右滑列舉一下!函數

var startx, starty;
    //得到角度
    function getAngle(angx, angy) {
        return Math.atan2(angy, angx) * 180 / Math.PI;
    };

    //根據起點終點返回方向 1向上 2向下 3向左 4向右 0未滑動
    function getDirection(startx, starty, endx, endy) {
        var angx = endx - startx;
        var angy = endy - starty;
        var result = 0;

        //若是滑動距離過短
        if (Math.abs(angx) < 2 && Math.abs(angy) < 2) {
            return result;
        }

        var angle = getAngle(angx, angy);
        if (angle >= -135 && angle <= -45) {
            result = 1;
        } else if (angle > 45 && angle < 135) {
            result = 2;
        } else if ((angle >= 135 && angle <= 180) || (angle >= -180 && angle < -135)) {
            result = 3;
        } else if (angle >= -45 && angle <= 45) {
            result = 4;
        }

        return result;
    }
    //手指接觸屏幕
    document.addEventListener("touchstart", function(e) {
        startx = e.touches[0].pageX;
        starty = e.touches[0].pageY;
    }, false);
    //手指離開屏幕
    document.addEventListener("touchend", function(e) {
        var endx, endy;
        endx = e.changedTouches[0].pageX;
        endy = e.changedTouches[0].pageY;
        var direction = getDirection(startx, starty, endx, endy);
        switch (direction) {
            case 0:
                alert("未滑動!");
                break;
            case 1:
                alert("向上!")
                break;
            case 2:
                alert("向下!")
                break;
            case 3:
                alert("向左!")
                break;
            case 4:
                alert("向右!")
                break;
            default:
        }
    }, false);

 

知道滑動方向如何判斷,那麼解決這個問題咱們能夠判斷是否滑動到底部或者頂部,假如滑動到底部,再往下滑動,就阻止滑動,往上滑動,就開啓滑動!滑動到頂部一個道理!總結代碼以下:測試

  $('#haorooms底層背景').bind("touchmove", function (e) {
            e.preventDefault();
        });
        $(".滾動的父親").bind("touchstart", function (events) {
            startY = events.originalEvent.changedTouches[0].pageY;
        });
        $(".滾動的父親 ul").bind("touchmove", function (e) {
            var ulheight = $(this).height();
            var scrollTop = $(this).scrollTop();
            var scrollheight = $(this)[0].scrollHeight;
            if (ulheight + scrollTop + 20 >= scrollheight) { //滾到底部20px左右
                $(".滾動的父親").bind("touchmove", function (event) {
                    moveEndY = event.originalEvent.changedTouches[0].pageY,
                            theY = moveEndY - startY;
                    if (Math.abs(theY) > Math.abs(theX) && theY > 0) { //用上面的abs()更加準確!這裏是判斷上滑仍是下滑!能夠用角度函數也能夠用上面絕對值方式!
                        $(".滾動的父親").unbind("touchmove");//滑動到底部再往上滑動,解除阻止!
                    }
                    if (Math.abs(theY) > Math.abs(theX) && theY < 0) {
                        event.preventDefault();//滑動到底部,再往下滑動,阻止滑動!
                    }
                })
            }
            if (scrollTop < 20) {//滾到頂部20px左右
                $(".滾動的父親").bind("touchmove", function (event) {
                    moveEndY = event.originalEvent.changedTouches[0].pageY,
                            theY = moveEndY - startY;
                    if (Math.abs(theY) > Math.abs(theX) && theY > 0) {
                        event.preventDefault();
                    }
                    if (Math.abs(theY) > Math.abs(theX) && theY < 0) {
                        $(".滾動的父親").unbind("touchmove");
                    }
                })
            }
        });

 

以上方法基本上可以阻止body的滾動,可是,有時候仍是會有問題,期待更好的解決方案!網站

張鑫旭的一種解決辦法

下面是張鑫旭的一個解決辦法,這裏我簡單的借用一下!this

CSS代碼:spa

.noscroll,
.noscroll body {
    overflow: hidden;
}
.noscroll body {
    position: relative;
}

 

js代碼:code

$.smartScroll = function(container, selectorScrollable) {
    // 若是沒有滾動容器選擇器,或者已經綁定了滾動時間,忽略
    if (!selectorScrollable || container.data('isBindScroll')) {
        return;
    }

    // 是不是搓瀏覽器
    // 本身在這裏添加判斷和篩選
    var isSBBrowser;

    var data = {
        posY: 0,
        maxscroll: 0
    };

    // 事件處理
    container.on({
        touchstart: function (event) {
            var events = event.touches[0] || event;

            // 先求得是否是滾動元素或者滾動元素的子元素
            var elTarget = $(event.target);

            if (!elTarget.length) {
                return;    
            }

            var elScroll;

            // 獲取標記的滾動元素,自身或子元素皆可
            if (elTarget.is(selectorScrollable)) {
                elScroll = elTarget;
            } else if ((elScroll = elTarget.parents(selectorScrollable)).length == 0) {
                elScroll = null;
            }

            if (!elScroll) {
                return;
            }

            // 當前滾動元素標記
            data.elScroll = elScroll;

            // 垂直位置標記
            data.posY = events.pageY;
            data.scrollY = elScroll.scrollTop();
            // 是否能夠滾動
            data.maxscroll = elScroll[0].scrollHeight - elScroll[0].clientHeight;
        },
        touchmove: function () {
            // 若是不足於滾動,則禁止觸發整個窗體元素的滾動
            if (data.maxscroll <= 0 || isSBBrowser) {
                // 禁止滾動
                event.preventDefault();
            }
            // 滾動元素
            var elScroll = data.elScroll;
            // 當前的滾動高度
            var scrollTop = elScroll.scrollTop();

            // 如今移動的垂直位置,用來判斷是往上移動仍是往下
            var events = event.touches[0] || event;
            // 移動距離
            var distanceY = events.pageY - data.posY;

            if (isSBBrowser) {
                elScroll.scrollTop(data.scrollY - distanceY);
                elScroll.trigger('scroll');
                return;
            }

            // 上下邊緣檢測
            if (distanceY > 0 && scrollTop == 0) {
                // 往上滑,而且到頭
                // 禁止滾動的默認行爲
                event.preventDefault();
                return;
            }

            // 下邊緣檢測
            if (distanceY < 0 && (scrollTop + 1 >= data.maxscroll)) {
                // 往下滑,而且到頭
                // 禁止滾動的默認行爲
                event.preventDefault();
                return;
            }
        },
        touchend: function () {
            data.maxscroll = 0;
        }    
    });

    // 防止屢次重複綁定
    container.data('isBindScroll', true);
};

 

html以下:htm

<aside id="aside" class="aside">
    <i class="aside-overlay hideAside"></i>
    <div class="aside-content">
        <div class="module module-filter-list">
            <div class="module-main scrollable">
                <ul id="filters" class="sort-ul">
                    .......
                </ul>
            </div>
        </div>
    </div>
</aside>

 

使用:

$('#aside').addClass('active');
$.smartScroll($('#aside'), '.scrollable');
$('html').addClass('noscroll');

 

你們能夠測試一下!

相關文章
相關標籤/搜索