web移動前端的click點透問題

在移動端開發中,有時會出現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、其餘推薦閱讀

1.在手持設備上使用 touchstart 事件代替 click 事件是否是個好主意?

2.【讀fastclick源碼有感】完全解決tap「點透」,提高移動端點擊響應速度

相關文章
相關標籤/搜索