1. 程式人生 > >H5移動頁面的touch事件與點選穿透問題

H5移動頁面的touch事件與點選穿透問題

先舉一個例子:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta content="width=device-width,height=device-height,initial-scale=1.0">
    <title>Title</title>
    <style>
        *{padding:0;margin:0;}html,body{width: 100%;height: 100%;}
        .mask {
            position: absolute;
            width: 100%;
            height: 100%;
            background: rgba(26,26,26,0.2);
        }
       a{
            display: block;
            width: 100%;
            height: 100%;
            font-size: 2rem;
        }
    </style>
</head>
<body>
    <div class="mask"></div>
    <a href="http://www.baidu.com">去百度</a>
</body>
<script src="jquery.js"></script>
<script>
    $(document).on('touchstart', '.mask', function() {
        $(this).hide();
    })
</script>
</html>

簡介:上邊例子中,a標籤連結到百度,a標籤上方漂浮這一個蒙層,js的功能是實現點選蒙層後蒙層消失。

效果:點選蒙層,蒙層消失;300毫秒後,下邊的a標籤的click事件被觸發,網頁跳轉到百度,即發生了事件穿透。

把js程式碼換成以下寫法:

<script>
    $(document).on('click', '.mask', function() {
        $(this).hide();
    })
</script>

效果:點選蒙層,蒙層消失,但存在300毫秒延遲。

解釋:

一.click與300ms延遲
移動瀏覽器提供一個特殊的功能:雙擊(double tap)放大

300ms的延遲就來自這裡,使用者碰觸頁面之後,需要等待一段時間來判斷是不是雙擊(double tap)動作,而不是立即響應單擊(click),等待的這段時間大約是300ms。

移動事件提供了touchstart、touchmove、touchend卻沒有提供tap支援,主流框架(庫)都是手動實現了自定義tap事件,以求消除300ms延遲,提高頁面響應速度。對於簡單的頁面,可以把touchstart或者touchend當作tap來用,但存在一些問題,比如手指接觸目標元素,按住不放,慢慢移出響應區域,會觸發touchstart事件執行對應的事件處理器(本不應該觸發),touchend事件也存在類似的問題。

此外,使用原生touch事件也存在點選穿透的問題,因為click是在touch系列事件發生後大約300ms才觸發的,混用touch和click肯定會導致點透問題,下面詳細介紹


二.點選穿透問題

點選蒙層(mask),蒙層消失後發現觸發了按鈕下面元素的click事件,蒙層繫結的是touch事件,而按鈕下面元素繫結的是click事件(a預設為click事件),touch事件觸發之後,蒙層消失,300ms後這個點的click事件觸發,事件的target自然就是蒙層下面的元素,蒙層此時已經消失。

②如果按鈕下面恰好是一個有href屬性的a標籤,那麼頁面就會發生跳轉,因為a標籤跳轉預設是click事件觸發,所以原理和上面的完全相同。


三、解決方法
①只用touch:把頁面內所有click全部換成touch事件(touchstart、’touchend’、’tap’),需要特別注意a標籤,a標籤的href也是click,需要去掉換成js控制的跳轉,或者直接改成span + tap控制跳轉。如果要求不高,不在乎滑走或者滑進來觸發事件的話,span + touchend就可以了,畢竟tap需要引入第三方庫

缺點:不利於seo(因為沒有a標籤,內鏈外鏈之類的也就沒有了)

②只用click。缺點:會帶來300ms延遲。

③使用fastclick消除300毫秒延遲,隨後只用click。比較好用的解決方案,只是多載入了幾K的資源。

④遮擋:給mask的消失做一個fade效果,類似jQuery裡的fadeOut,並設定動畫duration大於300ms,這樣當延遲的 click 觸發時,就不會“穿透”到下方的元素了。


注:程式碼中本人使用的是JQuery,如果是開發,推薦使用移動端的js庫zepto.js,用法跟JQuery差異不大,touchstart請換成tap(相當於pc端的click),但依然會存在延遲,解決方法如上。

tap:原生的touch事件本身是沒有tap的,js庫裡提供的tap事件都是模擬出來的,單次點選300ms內再次點選則判定為double tap。