滚动穿透问题体现在移动端弹出层滑动时,导致弹框下面页面的滚动。
方案一:
使用 preventDefault
阻止浏览器默认事件:
var modal = document.getElementById('modalBox');
modal.addEventListener('touchmove', function(e) {
e.preventDefault();
}, false);
该方案适用于弹框内容高度小于屏幕高度,即弹框内容不可滑动的场景。touchmove
比 touchstart
更加合适。因为 touchstart
会连点击事件都阻止。
方案二:
给 overflow: scroll;
的元素加上一个 class
(以 body
元素为例)。退出的时候去掉这个 class
。
// css 部分
modal_open {
position: fixed;
height: 100%;
}
// js 部分
document.body.classList.add('modal_open');
document.body.classList.remove('modal_open');
该解决方案会带来新的麻烦,如果原页面不滚动的情况下,使用很完美,如果原页面滚动到一定的位置,使用该方案后,关闭弹框原页面会出现滚动位置丢失,即scrollTop
属性值会变为 0。需优化该方案为方案三。
方案三:
对方案二进行优化,在弹框弹出时,对原页面滚动位置进行保存,弹框关闭前,将原页面滚动的位置设置回去。
// css 部分
.modal_open {
position: fixed;
height: 100%;
}
// js 部分
var ModalHelper = (function(bodyClass) {
var scrollTop;
return {
afterOpen: function() {
scrollTop = document.scrollingElement.scrollTop ||
document.documentElement.scrollTop ||
document.body.scrollTop;
document.body.classList.add(bodyClass);
document.body.style.top = -scrollTop + 'px';
},
beforeClose: function() {
document.body.classList.remove(bodyClass);
document.scrollingElement.scrollTop = document.documentElement.scrollTop = document.body.scrollTop = scrollTop;
}
};
})('modal_open');
// method
modalSwitch: function(){
let self = this;
if( self.switchFlag === 'close' ){
ModalHelper.afterOpen();
self.switchFlag = 'open';
}else{
ModalHelper.beforeClose();
self.switchFlag = 'close';
}
}
方案二达到的效果:
- 弹窗滚动的时候,下方的原
页面
是固定的无法滚动; - 原
页面
的滚动位置不会丢失; - 原
页面
有 scroll 事件;
参考:
https://juejin.im/post/5c2dc9cce51d45690a254b79