移動端點擊穿透問題由來
這要追溯至 2007 年初。蘋果公司在發(fā)布首款 iPhone 前夕导匣,遇到一個問題:當時的網(wǎng)站都是為大屏幕設(shè)備所設(shè)計的。于是蘋果的工程師們做了一些約定茸时,應對 iPhone 這種小屏幕瀏覽桌面端站點的問題贡定。這當中最出名的,當屬雙擊縮放(double tap to zoom)可都,這也是會有上述 300 毫秒延遲的主要原因缓待。雙擊縮放,顧名思義渠牲,即用手指在屏幕上快速點擊兩次旋炒,iOS 自帶的 Safari 瀏覽器會將網(wǎng)頁縮放至原始比例。 那么這和 300 毫秒延遲有什么聯(lián)系呢嘱兼? 假定這么一個場景。用戶在 iOS Safari 里邊點擊了一個鏈接贤徒。由于用戶可以進行雙擊縮放或者雙擊滾動的操作芹壕,當用戶一次點擊屏幕之后,瀏覽器并不能立刻判斷用戶是確實要打開這個鏈接接奈,還是想要進行雙擊操作踢涌。因此,iOS Safari 就等待 300 毫秒序宦,以判斷用戶是否再次點擊了屏幕睁壁。 鑒于iPhone的成功,其他移動瀏覽器都復制了 iPhone Safari 瀏覽器的多數(shù)約定互捌,包括雙擊縮放潘明,幾乎現(xiàn)在所有的移動端瀏覽器都有這個功能。之前人們剛剛接觸移動端的頁面秕噪,在欣喜的時候往往不會care這個300ms的延時問題钳降,可是如今touch端界面如雨后春筍,用戶對體驗的要求也更高腌巾,這300ms帶來的卡頓慢慢變得讓人難以接受遂填。
那神馬是移動端穿透呢铲觉?假如頁面上有兩個元素A和B。B元素在A元素之上吓坚。我們在B元素的touchstart事件上注冊了一個回調(diào)函數(shù)撵幽,該回調(diào)函數(shù)的作用是隱藏B元素。我們發(fā)現(xiàn)礁击,當我們點擊B元素盐杂,B元素被隱藏了,B在300ms后產(chǎn)生的click事件由于找不到B,B會把click事件強行加給A執(zhí)行客税,這個過程就叫點擊穿透况褪,動畫如下
分析A產(chǎn)生click事件的原因更耻,由于點擊B后B會依次發(fā)生touchstart--->touchend-->click事件测垛,但當B的touchstart事件產(chǎn)生后,B消失了秧均,B會把它的300ms后產(chǎn)生的click事件強加到它z軸下方的A上食侮,代碼如下:
<!DOCTYPE html>
<html lang="en">
<head>
? ? <meta charset="UTF-8">
?<!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> -->
? ? <meta http-equiv="X-UA-Compatible" content="ie=edge">
? ? <title>Document</title>
</head>
<body>
? ? <style>
? ? #A{
? ? ? ? font-size:50px;
? ? ? ? width:400px;
? ? ? ? height:400px;
? ? ? ? background:gray
? ? }
? ? #B{
? ? ? ? font-size:50px;
? ? ? ? width:400px;
? ? ? ? height:400px;
? ? ? ? background:blue;
? ? ? ? position:absolute;
? ? ? ? left: 200px;
? ? ? ? top: 200px;
? ? }
? ? </style>
<div id="A">A</div>
<div id="B">B:點我穿透A</div>
? ? <script>
? ? let A=document.getElementById('A')
? ? let B=document.getElementById('B')
? ? B.addEventListener('touchstart',function(){
? ? ? ? B.style.display="none"
? ? })
? ? A.addEventListener('click',function(){
? ? ? ? console.log('A:啊目胡!我被穿透了')
? ? })
? ? </script>
</body>
</html>
大家請注意我把meta標簽注釋了锯七,因為當我們在 meta標簽加上?width=device-width?和 user-scalable=0時,移動端的瀏覽器就會自動去掉click的事件300ms的延時誉己,因為我們已經(jīng)為用戶適配了頁面大小和阻止了用戶縮放眉尸,所有瀏覽器就不用判斷用戶雙擊縮放了,因此瀏覽器就自動取消了click事件300ms的延遲
那么如何消除點擊穿透呢巨双,大家先來看這張圖噪猾。
小編第一次學習解決移動端點擊穿透的時候,覺得這之間非常繞筑累,往往搞不清事件的根源袱蜡,后來用了簡單的數(shù)學分析,才覺得思路特別清晰慢宗,
首先我們先來看產(chǎn)生點擊穿透的必要條件:
1.meta標簽沒有width=device-width和?user-scalable=0
2.B(mask)蒙版在A之上坪蚁,且在點擊后B在300ms之前消失
3.B(mask)綁定的是touchstart事件,A綁定的是click事件
所以解決的方案無非就是不讓上述三種情況不發(fā)生而已镜沽,是不是瞬間腦子就靈光了敏晤。
解決方案:
1.meta?標簽設(shè)置?width=device-width?和?user-scalable=0
2.在整個項目中只用touchstart事件,缺點:a標簽的herf跳轉(zhuǎn)仍需要click事件缅茉。
3.在整個項目中只用click事件茵典,優(yōu)點:使用簡單,適合使用對用戶點擊事件響應實時性不高的? ? ? ? 應 用宾舅, 缺點:點擊仍有300ms的延遲统阿,不適合游戲類的應用
4.在點擊B后彩倚,不讓B立刻消失,給B添加一個漸進(fade)消失的動畫效果扶平,時間大于300ms? ? ? ? 就可以了
5.最后一個是我覺得是最好的解決方案帆离,消除300ms的延遲后,再使用click事件结澄,使用fastclick? ? ? ? ?(大小?10kB)這個庫來實現(xiàn)哥谷,只需要多加幾kB的大小,還是很劃算的
總結(jié):解決點擊穿透的方式還是比較多的麻献,具體使用那種方案還是結(jié)合實際項目才能決定