滑動穿透及問題滑動報錯Unable to preventDefault inside passive event listener出原因及解決/ 寫一個完美的彈出框
最近再寫移動端項目時候碰到了,移動端滑動的時候遇到滑動穿透問題,滑動穿透問題是很常見的移動端問題,一般都是在彈出框上滑動時導致底部頁面跟隨滑動,主要出現在ios端
這時候我們想當然的會在彈出框時使用阻止頁面默認行爲
//打開彈出框時
openDialog() {
document.body.addEventListener('touchmove',(e)=> {
e.preventDefault()
]})
}
這樣雖然解決了彈出框問題,卻導致全局的滑動默認事件都被阻止了,所以我們一般會在關閉時清除阻止
//關閉
openDialog() {
document.body.removeEventListener('touchmove',(e)=> {
e.preventDefault()
]})
}
但是這是錯的!!!
因爲移除監聽必須保證掛在和移除的方法是同一個,匿名函數顯然不符合這個條件,所以我們這麼寫’
prevent() {
e.preventDefault()
}
//打開彈出框時
openDialog() {
document.body.addEventListener('touchmove',this.e.preventDefault)
}
//關閉
openDialog() {
document.body.removeEventListener('touchmove',this.e.preventDefault)
}
這樣就可以了
所以爲什麼會出現Unable to preventDefault inside passive event listener 的報錯 ,都是因爲你掛載阻止默認阻止監聽,但是沒有移除監聽
至於爲什麼會出現這個報錯,我在最後寫了,現在繼續我們的任務是要做一個彈出框
上面這些雖然實現了彈出時不滑動背景但是有一個嚴重的問題彈框內部也不滑動了,這樣遇到內部需要滾動就無法實現 ,
到這裏我們肯定會想到把事件綁定在模態框裏上
<div class="overlay" @touchmove="prevent">
</div>
...
prevent() {
e.preventDefault()
}
//vue上有快捷的修飾符
<div class="overlay" @touchmove.prevent>
</div>
但是這樣在overlay的內部還是無法滑動,這時候機智的我們想到了把內容與overlay分開放
<div class="overlay" @touchmove="prevent">
</div>
...
prevent() {
e.preventDefault()
}
//vue上有快捷的修飾符
<div class="overlay" @touchmove.prevent style="
postion: fixed;
width: 100vw;
height: 100vh;
">
>
</div>
<div class="content" style="
postion: fixed;
bottom: 0;
overflow: scroll;
height: 200px;
background: #fff
">
</div>
但是我們驚奇的發現,內部確實可以滾動了,overlay不能滾動,但是如果content
裏面沒有超出的內容沒有出現的滾動條的時候, 滑動內部底層還是穿透滑動了
完美彈出框
在彈出框打開試,設置body屬性overflow: hidden!important
<body style="overflow: hidden!important">
...
<div class="overlay" @touchmove.prevent style="
postion: fixed;
width: 100vw;
height: 100vh;
">
>
</div>
<div class="content" style="
postion: fixed;
bottom: 0;
overflow: scroll;
height: 200px;
background: #fff
">
</div>
...
</body>
這時候我只想說一句完美! 最後使用的時候封裝一下,下次可以用
爲什麼會出現Unable to preventDefault inside passive … 解釋一下
不長篇大論,在我們使用addEventListener
時這個方法其實有三個參數
document.body.addEventListener('touchmove'//事件,()=> {}//監聽觸發事件,false//保證不使用preventDefault方法)
第三個參數的主要作用就是用來優化滑動的, 對於瀏覽器來說他並不知道你觸發的touchmove
時執行的函數中是否使用了preventDefault
方法,所以瀏覽器滑動事件的觸發必須等你的函數完全執行完,這樣就會導致滑動卡頓延遲 ,所以如果設置第三個屬性爲true
,就是告訴瀏覽器我方法裏保證不使用preventDefault
方法
重要的是在大部分的瀏覽器裏爲了優化默認都對body做了touchmove
事件做了true的處理,所以一旦你在body上使用了preventDefault方法而且還沒有在後面移除掉, 瀏覽器就覺得你騙了他,他就瘋狂給你彈錯,而且導致頁面卡住了
So… 一般情況下儘量不要使用preventDefault