移動端遮罩阻止滾動方案

一直有這樣的需求, 可是一直沒有好好解決過, 是時候完全解決它了.css

先說明一下基本的頁面結構html

  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

這是最多見的處理遮罩出現時, 頁面阻止滾動的方案, 也確實有必定的效果, 但有必定的缺陷, 首先添加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: none

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

touchmove

真正能解決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

相關文章
相關標籤/搜索