前言
之前一直做PC系統,目前做移動端也遇到一些問題,本文解決移動端滾動的糟心問題!
全域性滾動
全域性滾動即滾動是在body上的滾動。如果只有一個全域性滾動是沒有問題的,問題在於全域性滾動的頁面出現了彈窗 如下圖所示情景:
在此情況下的彈窗會出現如下問題:滾動穿透--固定彈窗
啥意思呢,就是在彈窗上點選或滑動的時候,底層的全域性滾動也會跟著滑動!!! 剛出現問題的時候也在網上查詢了一波,嘗試瞭如下方法:
- 彈窗時給body設定overflow:hidden;(缺點:ios沒用)
- 彈窗時給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
是肯定不行的。
結語
種一棵樹最好的時間是十年前,其次是現在。
如果有幫助請點贊喲~