zoukankan      html  css  js  c++  java
  • 移动端表层div滑动,导致底层body滑动(touchmove的阻止)

    body很长,可以滑动,body头部有一个模拟下拉的选择框,下拉选择有滚动轴

    我给body一个overflow:hidden和高度是没有用的。手机网站上背景还是可以滑动,然后我给body一个touchmove的preventdefault()阻止事件,body滑动阻止了,PC上面是可以了,但是手机上面滑动div还是会导致底部body的滑动,我给div 一个阻止冒泡的事件stopPropagation(),手机网站上面还是不可以。

    解决方案

    我经过反复测试,发现滚动轴滚到底部的时候,会触发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的滑动方向。

    除了上面方法判断手机端手机滑动方向,我这里再介绍一个方案,就是封装一个角度函数,通过角度函数来判断也还不错!我这里仅仅把这种方式实现上滑下滑左滑右滑列举一下!

    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的滚动,但是,有时候还是会有问题,期待更好的解决方案!

    张鑫旭的一种解决办法

    下面是张鑫旭的一个解决办法,这里我简单的借用一下!

    CSS代码:

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

    js代码:

    $.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如下:

    <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');

    大家可以测试一下!

  • 相关阅读:
    php模式设计之 工厂模式
    SDK以及部署的SDK的思路
    手机用fiddler抓包开发测试
    搭建GIT服务端
    TP5.0以上数据库增加数据异常
    lnmp一键安装后的配置改动建议
    TPshop5最新版 安装 nginx 开启PATHINFO 模式资源加载路径加载失败问题,适用tp3.2PATHINFO模式REWRITE模式
    jquery写拉动条
    JS(JQ)分页 个人查看,没注释
    ecshop 分页
  • 原文地址:https://www.cnblogs.com/hubgit/p/7391039.html
Copyright © 2011-2022 走看看