<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          移動端滾動穿透與滾動溢出解決方案

          共 6761字,需瀏覽 14分鐘

           ·

          2023-10-07 12:08

          點擊上方 前端Q,關(guān)注公眾號

          回復加群,加入前端Q技術(shù)交流群

          滾動穿透

          問題描述

          在移動端 WEB 開發(fā)的時候(小程序也雷同),如上錄屏所示,如果頁面超過一屏高度出現(xiàn)滾動條時,在 fixed 定位的彈窗遮罩層上進行滑動,它下面的內(nèi)容也會跟著一起滾動,看起來好像事件穿透到下面的DOM元素上一樣,我們姑且稱之為滾動穿透。

          問題原因

          能夠猜想是文檔(document)的滾動事件被觸發(fā)了,如果能禁用滾動事件就好辦了。

          案例偽代碼

          <div class="btn">點擊出現(xiàn)彈窗</div>

          <div class="popup">
            <div class="popup-mask"></
          div>
            <div class="popup-body popup-bottom">
              <div class="header">我是標題</div>
              <div class="content">
                <div>0</div>        
                <div>1</div>
                <div>...</div>
              </div>
            </div>

          </div>
          .popup-mask {
            background-color: rgba(0000.5);
            position: fixed;
            z-index: 998;
            top: 0;
            bottom: 0;
            left: 0;
            right: 0;
          }

          .popup-body {
            padding0 50px 40px;
            background-color: #fff;
            position: fixed;
            z-index: 999;
          }

          ? 解決方案A (touch-action)

          默認情況下,平移(滾動)和縮放手勢由瀏覽器專門處理,但是可以通過 CSS 特性 touch-action 來改變觸摸手勢的行為。摘取幾個 touch-action 的值如下。

          描述
          auto 啟用瀏覽器處理所有平移和縮放手勢。
          none 禁用瀏覽器處理所有平移和縮放手勢。
          manipulation 啟用平移和縮放手勢,但禁用其他非標準手勢,例如雙擊縮放。
          pinch-zoom 啟用頁面的多指平移和縮放。

          于是在 popup 元素上設(shè)置該屬性,禁用元素(及其不可滾動的后代)上的所有手勢就可以解決該問題了。

          .popup {
            touch-action: none;
          }

          Note: [無障礙設(shè)計] 阻止頁面縮放可能會影響視力不佳的人閱讀和理解頁面內(nèi)容,不過小程序本身好像就不可以縮放!

          ? 解決方案B (event.preventDefault)

          來自 W3C 的一個標準。

          大意是說,在 touchstart 和 touchmove 事件中調(diào)用 preventDefault 方法可以阻止任何關(guān)聯(lián)事件的默認行為,包括鼠標事件和滾動。

          因此我們可以這樣處理。
          Step 1、監(jiān)聽彈窗最外層元素(popup)的 touchmove 事件并阻止默認行為來禁用所有滾動(包括彈窗內(nèi)部的滾動元素)。
          Step 2、釋放彈窗內(nèi)的滾動元素,允許其滾動:同樣監(jiān)聽 touchmove 事件,但是阻止該滾動元素的冒泡行為(stopPropagation),使得在滾動的時候最外層元素(popup)無法接收到 touchmove 事件。

          const popup = document.querySelector('.popup')
          const scrollBox = document.querySelector('.content')

          popup.addEventListener('touchmove', (e) => {
            // Step 1: 阻止默認事件
            e.preventDefault()
          })

          scrollBox.addEventListener('touchmove', (e) => {
            // Step 2: 阻止冒泡
            e.stopPropagation()
          })

          滾動溢出

          問題描述

          如上錄屏所示,彈窗內(nèi)也含有滾動元素,在滾動元素滾到底部或頂部時,再往下或往上滾動,也會觸發(fā)頁面的滾動,這種現(xiàn)象稱之為滾動鏈(scroll chaining), 但是感覺滾動溢出(overscroll)這個名字更言辭達意。

          ? 解決方案A (overscroll-behavior)

          overscroll-behavior 是 CSS 的一個特性,允許控制瀏覽器滾動到邊界的表現(xiàn),它有如下幾個值。

          描述
          auto 默認效果,元素的滾動可以傳播到祖先元素。
          contain 阻止?jié)L動鏈,滾動不會傳播到祖先元素,但是會顯示節(jié)點自身的局部效果。例如 Android 上過度滾動的發(fā)光效果或 iOS 上的橡皮筋效果。
          none 與 contain 相同,但是會阻止自身的過度效果。

          所以可以這樣解決問題:

          .content {
            overscroll-behavior: none;
          }

          簡潔干凈高性能,不過 Safari 全系不支持,兼容性如下,有沒有感覺 Safari 就是現(xiàn)代版的 IE(偶然聽路人說的)!

          ? 解決方案B (event.preventDefault)

          借用 event.preventDefault 的能力,當組件滾動到底部或頂部時,通過調(diào)用 event.preventDefault 阻止所有滾動,從而頁面滾動也不會觸發(fā)了,而在滾動之間則不做處理。

          let initialPageY = 0

          scrollBox.addEventListener('touchstart', (e) => {
              initialPageY = e.changedTouches[0].pageY
          })

          scrollBox.addEventListener('touchmove', (e) => {
              const deltaY = e.changedTouches[0].pageY - initialPageY
              
              // 禁止向上滾動溢出
              if (e.cancelable && deltaY > 0 && scrollBox.scrollTop <= 0) {
                  e.preventDefault()
              }

              // 禁止向下滾動溢出
              if (
                  e.cancelable &&
                  deltaY < 0 && 
                  scrollBox.scrollTop + scrollBox.clientHeight >= scrollBox.scrollHeight
              ) {
                  e.preventDefault()
              }
          })

          解決方案完整 Demo

          https://github.com/Barrior/cases/blob/main/overscroll.html

          作者:Barrior

          https://segmentfault.com/a/1190000040675446


          往期推薦


          小紅書招技術(shù)比例超過BAT,新一線廠人才涌入!
          代碼變更風險可視化系統(tǒng)建設(shè)與實踐
          解析Node.js鏡像原理,輕松構(gòu)建高效CI/CD流程

          最后


          • 歡迎加我微信,拉你進技術(shù)群,長期交流學習...

          • 歡迎關(guān)注「前端Q」,認真學前端,做個專業(yè)的技術(shù)人...

          點個在看支持我吧

          瀏覽 156
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美在线黄片 | 做女人自拍视频在线播放 | 内射蜜臀| 日本黄色视频免费看 | 日本A片免费在线观看 |