移动端遮罩阻止滚动方案

一直有这样的需求, 但是一直没有好好解决过, 是时候彻底解决它了.

先说明一下基本的页面结构

  1. HTML
<body>
  <div class="container">
    <div class="main">
      <p>页面内容</p>
      <!-- 很多页面内容 -->
    </div>
    <div class="pop hidden">
      <p>遮罩内容</p>
      <!-- 很多遮罩内容 -->
    </div>
  </div>
</body>
复制代码
  1. CSS
html,body {
  height: 100%;
  padding: 0;
  margin: 0;
  /* touch-action: none; */
}
.container {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  overflow: auto;
}
.pop {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  background: rgba(0, 0, 0, .5);
  overflow: auto;
  padding: 30px 0;
  box-sizing: border-box;
}
.main { height: 2000px; }
.hidden { display: none; }
.toggle { pointer-events: none; }
复制代码
  1. 基本JS
var Dcontainer = document.querySelector('.container')
var Dmain = document.querySelector('.main')
var Dpop = document.querySelector('.pop')
复制代码

overflow:hidden

这是最常见的处理遮罩出现时, 页面阻止滚动的方案, 也确实有一定的效果, 但有一定的缺陷, 首先添加JS

Dmain.onclick = function() {
  // 显示遮罩
  if( Dpop.classList.contains('hidden') ) {
    Dpop.classList.remove('hidden')
  }
  Dcontainer.style.overflow = 'hidden'
}
Dpop.onclick = function() {
  // 隐藏遮罩
  if( !Dpop.classList.contains('hidden')) {
    Dpop.classList.add('hidden')
  }
  Dcontainer.style.overflow = 'auto'
}
复制代码

点击出现遮罩的时候控制高度为手机整屏高度的盒子overflow:hidden, 遮罩关闭的时候隐藏 这种方式在pc端和android上表现都不错, 但是ios自带了页面回弹, 如果在页面回弹的瞬间去滑动遮罩中需要滑动的内容则会出现无法滑动的问题, 实际上很多方法都适用于pc和android而只是不兼容ios, 比如下面这种

pointer-events: none

pointer-events CSS 属性指定在什么情况下 (如果有) 某个特定的图形元素可以成为鼠标事件的 target。

Dmain.onclick = function() {
  // 显示遮罩
  if( Dpop.classList.contains('hidden') ) {
    Dpop.classList.remove('hidden')
  }
  Dmain.classList.add('toggle')
}
Dpop.onclick = function() {
  // 隐藏遮罩
  if( !Dpop.classList.contains('hidden')) {
    Dpop.classList.add('hidden')
  }
  Dmain.classList.remove('toggle')
}
复制代码

一个简单的css属性即可解决, 但是遗憾的是它同样无法兼容ios

touchmove

真正能解决ios上遮罩问题的还是监听touchmove事件

var initialClientY;

function getInitialClientY(e) {
  initialClientY = e.targetTouches[0].clientY
  console.log('initialClientY: ' + initialClientY)
}

function preventDefault(e) {
  // Dpop.scrollHeight  Dpop的高度
  // Dpop.scrollTop     Dpop距离顶部的距离
  // Dpop.clientHeight  Dpop可见区域的高度
  var clientY = e.targetTouches[0].clientY - initialClientY;
  if(Dpop && Dpop.scrollTop === 0 && clientY > 0) {  // 手指向下滑动
    e.preventDefault()
  }
  if(Dpop && (Dpop.scrollHeight - Dpop.scrollTop <= Dpop.clientHeight) && clientY < 0) {  // 手指向上滑动
    e.preventDefault()
  }
  e.stopPropagation()
}
Dmain.onclick = function() {
  // 显示遮罩
  if( Dpop.classList.contains('hidden') ) {
    Dpop.classList.remove('hidden')
  }
  Dpop.addEventListener('touchstart', getInitialClientY)
  // 需要滚动的元素
  Dpop.addEventListener('touchmove', preventDefault)
}
Dpop.onclick = function() {
  // 隐藏遮罩
  if( !Dpop.classList.contains('hidden')) {
    Dpop.classList.add('hidden')
  }
  Dpop.removeEventListener('touchstart', getInitialClientY)
  // 需要滚动的元素
  Dpop.removeEventListener('touchmove', preventDefault)
}
复制代码

监听touchmove事件不仅可以解决滚动穿透问题, 还能阻止ios上自带的页面回弹效果, 这种方法不需要强行设置页面的外层容器为屏幕高度

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值