移动端开发时常常会碰到有全屏遮罩层的弹窗滚动穿透问题,网上大部分的解决方案是弹窗出现时给body绝对定位或者高度设置为100%,并隐藏超出部分。html
可是这些解决方法,都存在这样的问题:当页面有滚动时,弹出弹窗,页面会滚动至顶部。特别是当页面有其余根据document文档滚动距离而绝对定位元素时,会致使页面元素混乱。node
我通过查询相关文档和实践,发现可经过监听touchmove和touchstart事件,来达到背景不可滚动而弹出窗可滚动的目的。可看此demo,建议在移动设备上查看。git
下面详细讲解一下实现方法:github
当阻止了整个弹窗的touchmove默认事件后,背景将不再会滚动。bash
var node = document.querySelector('.forbid-scroll-wrap');
node.addEventListener('touchmove', function (e) {
e.preventDefault();
}, false);
复制代码
可是这样会致使弹窗内部也没法滚动。因此须要判断触发touchmove事件的元素是否为可滚动区域,代码优化以下:优化
var node1 = document.querySelector('.can-scroll-wrap'),
node2 = document.querySelector('.forbid-scroll-wrap');
node2.addEventListener('touchmove', function (e) {
var target = e.target;
if ($(target).parents(canScrollWrap).length === 0 && $(target) != node1) {
e.preventDefault();
}
}, false);
复制代码
以上只是解决了一个问题:滑动弹窗其余地方背景页面确实未跟随滚动,可是没去弹窗可滚动区域到底部或顶部后,再滑动,背景页面仍可跟随滚动。this
因此仍须要对可滚动区域的滑动事件作监听:若向上滑动时,已到底部,或向下滑动时已到顶部,则阻止滑动事件。代码以下:spa
node1.scrollTop = 0;
var offsetHeight = node1.offsetHeight,
scrollHeight = node1.scrollHeight;
node2.addEventListener('touchmove', function (e) {
var target = e.target;
if ($(target).parents(canScrollWrap).length === 0 && $(target) != node1) {
e.preventDefault();
}
}, false);
node1.addEventListener('touchmove', function (e) {
var changedTouches = e.changedTouches, canMove = false;
var scrollTop = this.scrollTop;
if (changedTouches.length > 0) {
var touch = changedTouches[0] || {};
var moveY = touch.clientY;
if (moveY > startY && scrollTop <= 0) {
canMove = false;
} else if (moveY < startY && scrollTop + offsetHeight >= scrollHeight) {
canMove = false;
}else{
canMove = true;
}
if (!canMove) {
e.preventDefault();
}
}
}, false);
node1.addEventListener('touchstart', function (e) {
var targetTouches = e.targetTouches || [];
if (targetTouches.length > 0) {
var touch = targetTouches[0] || {};
startY = touch.clientY;
}
}, false)
复制代码
弹窗关闭后,可解除全部禁止code
node1.addEventListener('touchstart',null,false);
node1.addEventListener('touchmove',null,false);
node2.addEventListener('touchmove',null,false);
复制代码
点此查看源码htm