在移動端開發中,有時會出現click點透的問題。javascript
1、什麼是click點透html
如下狀況,在B元素上有半透明紅色遮蓋層A,黃色B元素內有可點擊連接C。前端
tips:如下舉例僅針對webkit內核瀏覽器,全部效果須要在移動端進行查看(PC端不支持touch事件)。java
具體html代碼以下:git
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>移動端點透問題</title> <style> *{ margin: 0px; padding:0px; } #div1{ /*紅色半透明遮蓋層A*/ width: 300px; height: 300px; background-color: rgba(255,0,0,0.25); } #div2{ /*黃色內容層B*/ width: 240px; height: 240px; background-color: yellow; position: absolute; left: 30px; top: 30px; z-index: -1; } #console{ /*綠色狀態輸出框*/ border: 1px solid green; position: absolute; top: 300px; width: 100%; } </style> </head> <body> <div id="div1"></div> <div id="div2"> <a href="www.baidu.com">www.baidu.com</a> </div> <div id="console"></div> </body> </html>
在「移動端」,點擊事件一般採用touch相關事件來獲取高效率。現有需求,點擊遮蓋層A則隱藏A(點擊後隱藏,這一點很重要),則相關javascript代碼以下:github
var div1 = document.getElementById("div1"); var div2 = document.getElementById('div2'); var con = document.getElementById('console'); function handle(e){var tar = e.target,
eve = e.type; var ele = document.createElement("p"); ele.innerHTML = "target:"+ tar.id + " event:" + eve ; con.appendChild(ele); if(tar.id === "div1"){ div1.style.display = "none"; } } div1.addEventListener("touchend",handle); div1.addEventListener("touchstart",handle);
這段簡單的代碼在 C區域外點擊時是沒有任何問題的,頁面下方的log記錄控制檯內會出現以下內容:web
target:div1 event:touchstart
target:div2 event:touchend
然而,當在C區域進行點擊罩層A的時候,會發現跳到百度頁面了,也就是,原本點擊A,可是卻透過A,點擊到了B裏的連接!這就是傳說中的 click點透。瀏覽器
爲了更清楚的看到這個過程,咱們爲B綁定click事件,即若是B觸發了click事件,那麼說明,在A上的點擊最終點到了B上。在上面javascript清單上添加一行代碼以下:app
div2.addEventListener('click',handle);
點擊B區域,能夠看到頁面下方的log記錄控制檯內出現以下內容:框架
target:div1 event:touchstart
target:div1 event:touchend
target:div2 event:click
可見,在div1的事件觸發完畢後,div2也就是B區域神奇的捕獲到了click事件,而事實上咱們只點擊了div1。
2、點透出現的場景
剛纔舉例說明了什麼是點透,其實點透的出現場景能夠總結以下:
1.A/B兩個層上下z軸重疊。
2.上層的A點擊後消失或移開。(這一點很重要)
3.B元素自己有默認click事件(如a標籤) 或 B綁定了click事件。
在以上狀況下,點擊A/B重疊的部分,就會出現點透的現象。
2、爲何會出現點透
click延遲,延遲,仍是延遲。
在移動端不使用click而用touch事件代替觸摸是由於click事件有着明顯的延遲,具體touchstart與click的區別以下:
1.touchstart:在這個DOM(或冒泡到這個DOM)上手指觸摸開始即能當即觸發
2.click:在這個DOM(或冒泡到這個DOM)上手指觸摸開始,且手指不曾在屏幕上移動(某些瀏覽器容許移動一個很是小的位移值),且在這個在這個dom上手指離開屏幕,且觸摸和離開屏幕之間的間隔時間較短(某些瀏覽器不檢測間隔時間,也會觸發click)才能觸發
也就是說,事件的觸發時間按由早到晚排列爲:touchstart 早於 touchend 早於 click。亦即click的觸發是有延遲的,這個時間大概在300ms左右。
因爲咱們在touchstart階段就已經隱藏了罩層A,當click被觸發時候,可以被點擊的元素則是其下的B元素,根據click事件的觸發規則:
只有在被觸發時,當前有click事件的元素顯示,且在面朝用戶的最前端時,才觸發click事件。
因爲B綁定了click事件(或者B自己默認存在click事件),因此B的click事件被觸發,產生了點透的狀況。
3、解決方案
1.對於B元素自己沒有默認click事件的狀況(無a標籤等),應統一使用touch事件,統一代碼風格,而且因爲click事件在移動端的延遲要大不少,不利於用戶體驗,因此關於觸摸事件應儘可能使用touch相關事件。
2.對於B元素自己存在默認click事件的狀況,應及時取消A元素的默認點擊事件,從而阻止click事件的產生。即應在上例的handle函數中添加代碼以下:
if(eve == "touchend") e.preventDefault();
3.對於遮蓋浮層,因爲遮蓋浮層的點擊即便有小延遲也是沒有關係的,反而會有疑似更好的用戶體驗,因此這種狀況,能夠針對遮蓋浮層本身採用click事件,這樣就不會出現點透問題。
4、現有解決方案框架(庫)
1. 衆所周知,zepto的tap事件是有點透問題的,可是最新版的zepto已經修復了這個問題。
2. 在zepto修復問題以前,有fastclick、hammer等通用庫可使用。
其中最常使用的仍是fastclick,地址 :https://github.com/ftlabs/fastclick
5、其餘推薦閱讀