页面滑出了一个弹窗,我们用手指触摸屏幕滑动时,会发现弹窗下面的内容还是在滚动。


方案一:

找到的第一个方法就是当弹窗触发的时候,给 overflow: scroll: 的元素加上一个 class (一般都是 body 元素)。退出的时候去掉这个 class。下面为了方便,会直接用 body 元素来代指弹窗下方的元素。

  1. // css 部分
  2. modal_open {
  3. position: fixed;
  4. height: 100%;
  5. }
  6. // js 部分
  7. document.body.classList.add('modal_open');
  8. document.body.classList.remove('modal_open');

上面的这个方法可以解决滚动穿透问题,却也会带来新的问题。
即:

body 的滚动位置会丢失,也就是bodyscrollTop 属性值会变为 0。

这个新问题比起滚动穿透本身来说更加麻烦,所以这个方案是要进行优化的。

方案二:

既然添加 modal_open 这个 class 会使 body 的滚动位置会丢失,那么我们为什么不在滚动位置丢失之前先保存下来,等到退出弹窗的前在將这个保存下来的滚动位置在设置回去。然后就朝着这个方向开始 coding 。

  1. .modal_open {
  2. position: fixed;
  3. height: 100%;
  4. }
  1. /**
  2. * ModalHelper helpers resolve the modal scrolling issue on mobile devices
  3. * https://github.com/twbs/bootstrap/issues/15852
  4. */
  5. var ModalHelper = (function(bodyClass) {
  6. var scrollTop;
  7. return {
  8. afterOpen: function() {
  9. scrollTop = document.scrollingElement.scrollTop ||
  10. document.documentElement.scrollTop ||
  11. document.body.scrollTop;
  12. document.body.classList.add(bodyClass);
  13. document.body.style.top = -scrollTop + 'px';
  14. },
  15. beforeClose: function() {
  16. document.body.classList.remove(bodyClass);
  17. document.scrollingElement.scrollTop = document.documentElement.scrollTop = document.body.scrollTop = scrollTop;
  18. }
  19. };
  20. })('modal_open');
  21. // method
  22. modalSwitch: function(){
  23. let self = this;
  24. if( self.switchFlag === 'close' ){
  25. ModalHelper.afterOpen();
  26. self.switchFlag = 'open';
  27. }else{
  28. ModalHelper.beforeClose();
  29. self.switchFlag = 'close';
  30. }
  31. }

方案二可以达到以下效果:

  1. 弹窗滚动的时候,下方的 body 是固定的无法滚动;
  2. body 的滚动位置不会丢失;
  3. body 有 scroll 事件;

方案二可以适应绝大多数的弹窗需求,提测后测试方也没有在提其他问题,这个问题算是完美的解决了。不过我在这个过程有一个疑问:

IOS 自有的橡皮筋效果会导致页面会出现短暂卡顿现象,暂时没有找到原因,请教各位。

其他方案:

使用 preventDefault 阻止浏览器默认事件:

  1. var modal = document.getElementById('modalBox');
  2. modal.addEventListener('touchmove', function(e) {
  3. e.preventDefault();
  4. }, false);

这个方案只适用于这个弹窗本身的高度小于屏幕的高度,即不可滚动的时候。touchmovetouchstart 更加合适。因为 touchstart 会连点击事件都阻止。
使用插件:
对于插件我的态度是,除非是自己实现起来太复杂,否则还是自己花点时间去实现。原因有二:

  1. 使用插件就意味着需要引入的文件至少多了一个。
  2. 插件过多,担心日后项目升级维护成本加大。

参考

  1. developer.mozilla.org/en-US/docs/…
  2. uedsky.com/2016-06/mob…