在移動端開發的時候,咱們有時候會遇到這樣一個bug:點擊關閉遮罩層的時候,遮罩層下面的帶有點擊的元素也會被觸發,給人一種擊穿了頁面的感受,這是爲何呢?javascript
爲了讓你們更直觀的看到效果,我復現了bug,並錄製了一個gif。供你們參考:css
上圖事例js部分代碼html
var show = document.getElementById('show') // 打開按鈕
var mask = document.getElementById('mask') // 遮罩層
var btn = document.getElementById('btn') // 關閉按鈕
show.onclick = function () {
mask.style.display = 'block'
}
btn.addEventListener('touchstart', function () {
mask.style.display = 'none'
}, false)
</body>
</html>
複製代碼
咱們先來看一段代碼:(如下代碼需在移動端上運行)java
<div id="btn">我是一個按鈕</div>
複製代碼
var btn = document.getElementById('btn')
btn.addEventListener('touchstart', function () {
console.log('start')
}, false)
btn.addEventListener('touchmove', function () {
console.log('move')
}, false)
btn.addEventListener('touchend', function () {
console.log('touchend')
}, false)
btn.addEventListener('click', function () {
console.log('click')
}, false)
複製代碼
以上代碼會出現2種運行狀況git
看到這裏相信你們都明白了,因爲「關閉彈框」按鈕綁定的事件是touch,a標籤是click事件,在touch事件觸發後,咱們彈出框的遮罩層就消失了,這時候的click事件就被a標籤給捕獲到了,造成了擊穿的效果。github
btn.addEventListener('touchend', function (e) {
mask.style.display = 'none'
e.preventDefault()
}, false)
複製代碼
在執行 touchstart 和 touchend 事件時,隱藏執行完隱藏命令後,當即阻止後續事件(推薦在touchend時,阻止後續的默認事件)性能
btn.addEventListener('click', function () {
mask.style.display = 'none'
}, false)
複製代碼
這個方法簡單,就是交互的效率沒有click事件高,另外,用戶在touch的時候,有可能微微滑動了一下,就會沒法觸發點擊事件。影響用戶體驗。動畫
btn.addEventListener('touchend', function () {
setTimeout(function () {
mask.style.display = 'none' // 可使用fadeOut動畫
}, 300)
}, false)
複製代碼
點擊以後,咱們不當即隱藏。讓遮罩在350ms毫秒內淡出消失。(我爲了演示方便就沒有添加動畫了,採用了定時器方法。)ui
click.setAttribute('style', 'pointer-events:none')
mask.style.display = 'none'
setTimeout(function () {
click.setAttribute('style', 'pointer-events:auto')
}, 350)
複製代碼
這樣作法是,在遮罩消失以前,先讓a標籤忽略點擊事件,這樣遮罩層的點擊事件,就不會被a標籤捕獲到。仍是等350毫秒以後,再次賦予a標籤的點擊能力。這個方法跟方法三原理類似,只是利用了不一樣的css屬性而已。我的以爲方法三比較好一點。方法四有明顯的2個缺點:spa
一、遮罩層下面可能有多個帶有事件的元素,那麼你須要給全部可點擊元素添加pointer-events屬性 而後刪除。不只容易出錯,還影響性能
二、若是用戶在350毫秒內點擊了元素,會形成頁面失效的錯覺,影響體驗。
這個庫的引用方法,在我上一篇文章中已經講到。fastClick的原理就是使用了方法一的作法。fastClick 在 touchend 階段 調用 event.preventDefault,而後經過 document.createEvent 建立一個 MouseEvents,而後 經過 eventTarget.dispatchEvent 觸發對應目標元素上綁定的 click 事件。
後來有讀者提了一個fastClick的bug。在這裏我貼一下解決方案的地址