(转转转)web移动端浮层滚动阻止window窗体滚动JS/CSS处理

一、温故而知新

之前有写过在PC端“子元素scroll父元素容器不跟随滚动”的实现,原理是滚动到边缘通过preventDefault()阻止浏览器的默认行为达到我们想要的效果。

最近做移动端项目,遇到个类似的需求,就是,在众多web浏览器中,当我们出现一个浮层,浮层里面也有滚动条的时候,且有部分背景半透明的时候,就会发现,当我们滚动浮层里面的小滚动条的时候,背后整个页面都跟着一起滚走了。

后来,以为会和PC端一样,直接给<html>标签设置一个overflow:hidden声明就可以干掉窗体的滚动条,结果发现自己有些天真了。

后来经过一些研究以及测试,得到了下面这种双管齐下的处理方法。

二、阻止移动端窗体滚动的JS/CSS处理

首先CSS层面,在<html>标签上增加一个类名,例如noscroll,然后配合如下CSS和JS代码:

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

然后,当浮层出现的时候:

$('html').addClass('noscroll');

当浮层隐藏的时候:

$('html').removeClass('noscroll');

可以让一部分浏览器的窗体不能滚动,但不包括Safari等浏览器,怎么办呢?

我们可以在浮层touchmove的时候,阻止默认事件达到避免滚动的问题,例如:

$('aside').on('touchmove', function(event) {
    event.preventDefault();
});

这种处理兼容性强,效果最好,但是有一个问题,就是如果浮层自己也有滚动,那么这种处理会让浮层里面自己的滚动行为也无法触发,因此,我们的处理要更进一步,如下:

  1. 当手指touchstart的元素不是滚动容器同时不失容器的子元素的时候,阻止默认行为,;
  2. 如果手指touchstart的元素是滚动容器或者容器子元素的时候,不阻止默认行为,但不包括滚动到容器边缘的时候。

根据上述原理,我自己抽象了一个简单的方法,方法名和语法如下,完整代码见这里

$.smartScroll(container, selectorScrollable);

依赖Zepto.js或者jQuery.js,其中:
container表示委托的浮层容器元素($包装器对象),或者页面其他比较祖先的元素,但是,非常不建议使用$(document)或者$(document.body)等对象作为委托容器,因为可能会出现类似下面这样的错误提示:

Unable to preventDefault inside passive event listener due to target being treated as passive.

浏览器可能会把这些窗体元素的组织默认行为认为是不可取的消极的,会不被支持。

selectorScrollable表示container中可以滚动的元素的选择器,表示真正的滚动的主体。

$.smartScroll()方法的完整代码可以参见演示demo,您可以狠狠地点击这里:浮层元素滚动窗体不滚动的CSS/JS处理demo

原文地址:https://www.cnblogs.com/dexjinkey/p/6839950.html