弹出层内容滚动引发底层页面滚动的BUG处理

背景描述

页面上有个弹出层,弹出层内容较多需要滚动展示。若不做任何特殊处理的话,效果如下:

pc展示

模拟器上面显示更糟糕,当底下页面滚动时,浮层的内容甚至停止了滚动(问号脸)

第一次解决

尝试使用css来解决这个问题 打开弹层的时候给html添加以下样式

.noScroll body{
  overflow: hidden;
  position: relative;
}
复制代码
$('html').addClass('noscroll');
复制代码

结果说明

  1. pc上面的问题得到了很好的解决,已经正常了
  2. 手机上面完全无效哇?,看来手机上面还得另谋出路

第二次解决

当打开弹框的时候将除弹框底部的内容高度设为100%甚至隐藏底部就不会滚动了(事实表明图样图森破?),这样解决会引发两个问题:由于我们的弹层是半透明的打开弹层后会明显感觉我们的底部内容变化了,体验不好;另一个是关闭弹层后需要手动设置页面的滚动条为打开弹层前的位置。但这种简单粗暴的思路也有适合的时候:比如说弹层遮罩完全不透明;再比如说弹层展示为铺满整个屏幕。由于自己需求都不符合,又去思考别的解决思路~-_-~

最终解决思路

弹出层可滚动元素滚动时,阻止不可滚动元素的滚动事件,通过监听不可滚动元素的mousemove事件,在需要的时候阻止该元素的默认事件来实现。具体代码如下(很大程度上借鉴了张鑫旭的一篇文章,最下面有文章地址):

/**
 * 处理BUG:浮层滚动的时候下方页面内容随着滚动
 * @param container 浮层外层容器
 * @param selectorScrollable 浮层内滚动元素选择器
 */
$.onlyInnerScroll = function (container, selectorScrollable) {
  // 如果没有滚动容器选择器,或者已经绑定了滚动时间,忽略
  if (!selectorScrollable || container.data('isBindScroll')) {
    return;
  }
  var $scrollEle = $(selectorScrollable);
  // 移动端touch重写
  var startX, startY;

  var stopPopScroll = function (e) {
    e.stopPropagation();
    var $targetEle = $(e.target);
    if (!$targetEle.length) {
      return;
    }

    // 若当前滚动的元素是不是可滚动元素本身也不是滚动元素的子元素,则阻止滚动事件
    if (!$targetEle.is(selectorScrollable) && $scrollEle.has(e.target).length === 0) {
      console.log('已经阻止滚动事件');
      e.preventDefault();
      return false;
    }
  };

  container.on({
    'touchmove': function (e) {
      stopPopScroll(e);
    },
    'scroll': function (e) {
      stopPopScroll(e);
    }
  });

  $scrollEle.on({
    'touchstart': function (e) {
      startX = e.originalEvent.changedTouches[0].pageX;
      startY = e.originalEvent.changedTouches[0].pageY;
    },
    'touchmove': function (e) {
      e.stopPropagation();

      var deltaX = e.originalEvent.changedTouches[0].pageX - startX;
      var deltaY = e.originalEvent.changedTouches[0].pageY - startY;

      // 只能纵向滚
      if (Math.abs(deltaY) < Math.abs(deltaX)) {
        e.preventDefault();
        return false;
      }

      var box = $(this).get(0);

      if ($(box).height() + box.scrollTop >= box.scrollHeight) {
        if (deltaY < 0) {
          e.preventDefault();
          return false;
        }
      }
      if (box.scrollTop === 0) {
        if (deltaY > 0) {
          e.preventDefault();
          return false;
        }
      }
      // 会阻止原生滚动
      // return false;
    }
  });

  // 防止多次重复绑定
  container.data('isBindScroll', true);
};
复制代码
// 方法调用
$.onlyInnerScroll($('#pop-mod'), '.pop-form');
复制代码

希望可以帮到你~


  1. 滚动原理推荐阅读由弹出层引发对滚动原理的讨论

  2. 参考张鑫旭的文章web移动端浮层滚动阻止window窗体滚动JS/CSS处理

转载于:https://juejin.im/post/5c18cb045188253ff1477937

你可能感兴趣的:(移动开发)