解決移動端滾動穿透

no-simple發表於2019-01-24

前言

之前一直做PC系統,目前做移動端也遇到一些問題,本文解決移動端滾動的糟心問題!

全域性滾動

全域性滾動即滾動是在body上的滾動。如果只有一個全域性滾動是沒有問題的,問題在於全域性滾動的頁面出現了彈窗 如下圖所示情景:

解決移動端滾動穿透
在此情況下的彈窗會出現如下問題:

滾動穿透--固定彈窗

啥意思呢,就是在彈窗點選或滑動的時候,底層的全域性滾動也會跟著滑動!!! 剛出現問題的時候也在網上查詢了一波,嘗試瞭如下方法:

  1. 彈窗時給body設定overflow:hidden;(缺點:ios沒用)
  2. 彈窗時給body設定position:fixed;(缺點:滾動位置會丟失,ios沒用)

針對此情景的完美解決方法是:

給彈窗加上@touchmove.stop.prevent,即可阻止touchmove事件傳遞到body,也就解決了滾動穿透

滾動穿透——滾動彈窗

解決移動端滾動穿透

還是這張圖,情況就是彈窗裡也是有滾動的!!!如果使用了@touchmove.stop.prevent,那的確可以解決滾動穿透的問題,但是由於阻止了@touchmove,自身也無法滾動了,不信自己寫demo試試~

那針對此種情況完美解決方案是: 在彈窗開啟的時候給body的全域性滾動設定position:fixed屬性,並設定top值;由於設定了fixed屬性,那在彈窗的時候body就沒有滾動條了。此時如果這麼設定會發現body雖然沒有了滾動穿透,但是原來的位置丟失了。所以再給body設定fixed屬性的時候,要把當前的滾動位置賦值給css的top屬性,那在視覺上就沒有任何變化了。

      fixedBody () {
        let scrollTop = document.body.scrollTop || document.documentElement.scrollTop
        document.body.style.cssText += 'position:fixed;width:100%;top:-' + scrollTop + 'px;'
      }
複製程式碼

那在彈窗關閉的時候如何處理呢? 彈窗關閉的時候則要清除fixed固定定位和top值;並設定其滾動位置位置top值,則又恢復了滾動功能,而且視覺上沒有任何變化,是目前最完美的解決方案!

      looseBody () {
        let body = document.body
        body.style.position = ''
        let top = body.style.top
        document.body.scrollTop = document.documentElement.scrollTop = -parseInt(top)
        body.style.top = ''
      }
複製程式碼

總結

以上兩種方案解決了固定彈窗和滾動彈窗對於body全域性滾動的影響。文章末尾在針對vue做一個自定義指令封裝

區域性滾動

區域性滾動,還是剛才的圖片,在彈窗裡的滾動,在Android上滾動沒啥問題,但是在ios區域性滾動有時就會實現。

復現步驟:

  • ①從滾動區域外從上往下化
  • ②在滑動滾動區域,發現滾動竟然失效了!!!活見鬼了....這TM還是原生屬性。多重發幾次,一定可以復現的。
    解決移動端滾動穿透

解決辦法: 使用外掛better-scroll,大傢伙自己研究文件就行。

vue封裝

vue:

    directives: {
      fixed: {
        // inserted 被繫結元素插入父節點時呼叫
        inserted () {
          let scrollTop = document.body.scrollTop || document.documentElement.scrollTop
          document.body.style.cssText += 'position:fixed;width:100%;top:-' + scrollTop + 'px;'
        },
        // unbind 指令與元素解綁時呼叫
        unbind () {
          let body = document.body
          body.style.position = ''
          let top = body.style.top
          document.body.scrollTop = document.documentElement.scrollTop = -parseInt(top)
          body.style.top = ''
        }
      }
    },
複製程式碼

自定義指令使用 html:

<div  v-if="isShowRecordModal" v-fixed>
    ....
    ....
</div>
複製程式碼

該指令的注意點是必須使用v-if開啟關閉彈窗,因為該指令依賴於dom的插入和登出,使用v-show是肯定不行的。

結語

種一棵樹最好的時間是十年前,其次是現在。

如果有幫助請點贊喲~

相關文章