一直有这样的需求, 可是一直没有好好解决过, 是时候完全解决它了.css
先说明一下基本的页面结构html
<body>
<div class="container">
<div class="main">
<p>页面内容</p>
<!-- 不少页面内容 -->
</div>
<div class="pop hidden">
<p>遮罩内容</p>
<!-- 不少遮罩内容 -->
</div>
</div>
</body>
复制代码
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; }
复制代码
var Dcontainer = document.querySelector('.container')
var Dmain = document.querySelector('.main')
var Dpop = document.querySelector('.pop')
复制代码
这是最多见的处理遮罩出现时, 页面阻止滚动的方案, 也确实有必定的效果, 但有必定的缺陷, 首先添加JSandroid
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, 好比下面这种ios
pointer-events CSS 属性指定在什么状况下 (若是有) 某个特定的图形元素能够成为鼠标事件的 target。bash
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属性便可解决, 可是遗憾的是它一样没法兼容iosspa
真正能解决ios上遮罩问题的仍是监听touchmove事件code
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上自带的页面回弹效果, 这种方法不须要强行设置页面的外层容器为屏幕高度htm