1. 程式人生 > >移動端事件點透問題

移動端事件點透問題

get HR round 存在 綁定 離開 spa 就會 區別

在移動WEB開發中,有時候可能會出現點透問題,本隨筆將圍繞這個TAP點透問題,詳細的講述以下幾點:

  到底什麽是點透?為什麽會出現點透?如何避免出現點透?如果不可避免的出現了,如何解決解決點透問題?(我說的是移動端,不是pc端

1、什麽是點透?

以下情況,在B元素上有半透明灰色遮蓋層A,黃色B元素內有可點擊鏈接。

技術分享圖片

布局代碼如下

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>點透問題</title>
    <style>
        *{
            margin: 0px;
            padding:0px;
        }
        #A{ /*灰色色半透明遮蓋層A*/
            width: 300px;
            height: 300px;
            background-color: rgba(255,0,0,0.25);        
        }
        #B{ /*黃色內容層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="A"></div>
    <div id="B">
       <a href="https://www.cnblogs.com/shizk/">https://www.cnblogs.com/shizk/</a>
    </div>
    <div id="console"></div>
</body>
</html>

在“移動端”,點擊事件通常采用touch相關事件來獲取高效率。現有需求,點擊遮蓋層A則隱藏A(點擊後隱藏,這一點很重要),則相關javascript代碼如下:

var div1 = document.getElementById("A");
var div2 = document.getElementById(‘B‘);
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);

這段簡單的代碼在 鏈接區域外點擊時是沒有任何問題的,頁面下方的log記錄控制臺內會出現如下內容:
target:div1 event:touchstart
target:div2 event:touchend 

當在鏈接區域進行點擊罩層A的時候,會發現跳到我的博客頁面了,也就是,本來點擊A,但是卻透過A,點擊到了B裏的鏈接!這就是傳說中的 click點透。

為了更清楚的看到這個過程,我們為B綁定click事件,即如果B觸發了click事件,那麽說明,在A上的點擊最終點到了B上,代碼如下:

div2.addEventListener(‘click‘,handle);

點擊B區域,可以看到頁面下方的log記錄控制臺內出現如下內容:
target:div1 event:touchstart
target:div1 event:touchend
target:div2 event:click
可見,在div1的事件觸發完畢後,div2也就是B區域捕獲到了click事件,而事實上我們只點擊了div1。

2、為什麽會出現點透?

一、出現的場景:

a、A/B兩個層上下z軸重疊。

b、上層的A點擊後消失或移開。(*

c、B元素本身有默認click事件(如a標簽) 或 B綁定了click事件。

在以上情況下,點擊A/B重疊的部分,就會出現點透的現象。

二、為什麽會出現:

click延遲 ! click延遲 ! click延遲 !
在移動端不使用click而用touch事件代替觸摸是因為click事件有著明顯的延遲,具體touchstart與click的區別如下:
touchstart:在這個DOM(或冒泡到這個DOM)上手指觸摸開始即能立即觸發
click:在這個DOM(或冒泡到這個DOM)上手指觸摸開始,且手指未曾在屏幕上移動(某些瀏覽器允許移動一個非常小的位移值),且在這個在這個dom上手指離開屏幕,且觸摸和離開屏幕之間的間隔時間較短(某些瀏覽器不檢測間隔時間,也會觸發click)才能觸發
也就是說,事件的觸發時間按由早到晚排列為:touchstart 早於 touchend 早於 click。亦即click的觸發是有延遲的,這個時間大概在300ms左右。
由於我們在touchstart階段就已經隱藏了罩層A,當click被觸發時候,能夠被點擊的元素則是其下的B元素,根據click事件的觸發規則

3、如何避免出現點透和解決點透問題?

對於B元素本身沒有默認click事件的情況(無a標簽等),應統一使用touch事件,統一代碼風格,並且由於click事件在移動端的延遲要大很多,不利於用戶體驗,所以關於觸摸事件應盡量使用touch相關事件。
對於B元素本身存在默認click事件的情況,應及時取消A元素的默認點擊事件,從而阻止click事件的產生。即應在上例的handle函數中添加代碼如下:

if(eve == "touchsend") e.preventDefault();

對於遮蓋浮層,由於遮蓋浮層的點擊即使有小延遲也是沒有關系的,反而會有疑似更好的用戶體驗,所以這種情況,可以針對遮蓋浮層自己采用click事件,這樣就不會出現點透問題。

4、現有解決框架:

zepto的tap事件是有點透問題的,但是最新版的zepto已經修復了這個問題。
在zepto修復問題之前,有fastclick、hammer等通用庫可以使用。

移動端事件點透問題