页面滑出了一个弹窗,我们用手指触摸屏幕滑动时,会发现弹窗下面的内容还是在滚动。
方案一:
找到的第一个方法就是当弹窗触发的时候,给 overflow: scroll:
的元素加上一个 class
(一般都是 body
元素)。退出的时候去掉这个 class
。下面为了方便,会直接用 body
元素来代指弹窗下方的元素。
// css 部分
modal_open {
position: fixed;
height: 100%;
}
// js 部分
document.body.classList.add('modal_open');
document.body.classList.remove('modal_open');
上面的这个方法可以解决滚动穿透问题,却也会带来新的问题。
即:
body
的滚动位置会丢失,也就是body
的scrollTop
属性值会变为 0。
这个新问题比起滚动穿透本身来说更加麻烦,所以这个方案是要进行优化的。
方案二:
既然添加 modal_open
这个 class
会使 body
的滚动位置会丢失,那么我们为什么不在滚动位置丢失之前先保存下来,等到退出弹窗的前在將这个保存下来的滚动位置在设置回去。然后就朝着这个方向开始 coding 。
.modal_open {
position: fixed;
height: 100%;
}
/**
* ModalHelper helpers resolve the modal scrolling issue on mobile devices
* https://github.com/twbs/bootstrap/issues/15852
*/
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';
}
}
方案二可以达到以下效果:
- 弹窗滚动的时候,下方的
body
是固定的无法滚动; body
的滚动位置不会丢失;body
有 scroll 事件;
方案二可以适应绝大多数的弹窗需求,提测后测试方也没有在提其他问题,这个问题算是完美的解决了。不过我在这个过程有一个疑问:
IOS 自有的橡皮筋效果会导致页面会出现短暂卡顿现象,暂时没有找到原因,请教各位。
其他方案:
使用 preventDefault
阻止浏览器默认事件:
var modal = document.getElementById('modalBox');
modal.addEventListener('touchmove', function(e) {
e.preventDefault();
}, false);
这个方案只适用于这个弹窗本身的高度小于屏幕的高度,即不可滚动的时候。touchmove
比 touchstart
更加合适。因为 touchstart
会连点击事件都阻止。
使用插件:
对于插件我的态度是,除非是自己实现起来太复杂,否则还是自己花点时间去实现。原因有二:
- 使用插件就意味着需要引入的文件至少多了一个。
- 插件过多,担心日后项目升级维护成本加大。