登錄 / 注冊

H5案例分享:Touch穿透

0評論 2017-06-19 10:38:28

收藏 | 點贊

  

一、前言

   相信很多移動開發(fā)者都有這樣一個體會,那就是我們在移動端點擊事件click對比touchend會有延遲,這是為什么呢?

   其實這是因為覽器在click后會等待約300ms去判斷用戶是否有雙擊行為,手機(jī)需要知道用戶是不是想雙擊放大網(wǎng)頁內(nèi)容。如果300ms內(nèi)沒有再一次click,那么就判定這是一次單擊行為,所以我們基本上都用(touchstart/touchend),但是這些事件在執(zhí)行完之后還會執(zhí)行一次click事件。(至于具體的原因這要從JS事件監(jiān)聽機(jī)制的根本的講起,解釋起來太麻煩,感興趣的同學(xué)可以動手了解一下,我們這里就不做過多說明了)。

 

二、touch事件的來源

   PC網(wǎng)頁上的大部分操作都是用鼠標(biāo)的,即響應(yīng)的是鼠標(biāo)事件,包括mousedown、mouseup、mousemove和click事件。一次點擊行為,事件的觸發(fā)過程為:mousedown -> mouseup -> click 三步。

   因為手機(jī)上沒有鼠標(biāo),所以就用觸摸事件touch去實現(xiàn)類似的功能。touch事件包含touchstart、touchmove、touchend,注意手機(jī)上并沒有tap事件。手指觸發(fā)觸摸事件的過程為:touchstart -> touchmove -> touchend。

   手機(jī)上沒有鼠標(biāo),但不代表手機(jī)不能響應(yīng)mouse事件,其實是借助touch去觸發(fā)mouse事件。有人在PC和手機(jī)上對事件做了對比實驗,以說明手機(jī)對touch事件相應(yīng)速度快于mouse事件。

QQ截圖20170619105124.jpg

   從上面的圖表對比中我們可以看出在手機(jī)上,當(dāng)我們手觸碰屏幕時,要過300ms左右才會觸發(fā)mousedown事件,所以click事件在手機(jī)上看起來就像慢半拍一樣。

 

三、點擊穿透的場景

   點擊穿透的現(xiàn)象主要分為四種:

 

   1.點擊蒙層(Mask Layer)上的關(guān)閉按鈕,蒙層消失后發(fā)現(xiàn)觸發(fā)了按鈕下面元素的click事件。
   蒙層的關(guān)閉按鈕綁定的是touch事件,而按鈕下面元素綁定的是click事件,touch事件觸發(fā)之后,蒙層消失了,300ms后這個點的click事件出發(fā),事件的目標(biāo)元素自然就變成了按鈕下面的元素,因為按鈕跟蒙層一起消失了。

 

   2.如果按鈕下面恰好是一個有href屬性的a標(biāo)簽,那么頁面就會發(fā)生跳轉(zhuǎn),因為a標(biāo)簽跳轉(zhuǎn)默認(rèn)是click事件觸發(fā),所以穿透原理和上面的完全相同。

 

   3.如果按鈕下面恰好是文本框input或文本域textarea,則文本框或文本域就會獲取焦點,穿透原理和上面的相同。

   4.這次沒有蒙層,直接點擊頁內(nèi)按鈕跳轉(zhuǎn)至新頁,然后發(fā)現(xiàn)新頁面中對應(yīng)位置元素的click事件被觸發(fā)了。


   和蒙層的道理一樣,js控制頁面跳轉(zhuǎn)的邏輯如果是綁定在touch事件上的,而且新頁面中對應(yīng)位置的元素綁定的是click事件,而且頁面在300ms內(nèi)完成了跳轉(zhuǎn),三個條件同時滿足,就出現(xiàn)這種情況了。

   其他的點擊穿透的例子還有很多,我就不一一細(xì)說了。

 

四、Touch穿透的解決辦法

   1.延遲

   蒙層被點擊后延時至少300ms再在徹底隱藏掉蒙層顯示下層的內(nèi)容,缺點是隱藏蒙層變慢了,350ms還是能感覺到慢的,但是這種方法只需要針對蒙層做處理就行了,改動非常小,如果要求不高的話,用這個比較省時省力。

 

   2.增加中間蒙層

   我們還可以動態(tài)地在觸摸位置生成一個透明的元素,這樣當(dāng)上層元素消失而延遲的click來到時,它點擊到的是那個透明的元素,就不會“穿透”到下面去了,然后再在一定的延遲后將生成的透明元素移除。

 

   3.利用pointer-events方法

   pointer-events是CSS3中的屬性,它有很多取值,auto | none | visiblepainted | visiblefill | visiblestroke | visible | painted | fill | stroke | all,有用的主要是auto和none,其他屬性值為SVG服務(wù)。

   當(dāng)pointer-events取值為auto時,效果與pointer-events屬性未指定時的表現(xiàn)效果相同;當(dāng)取值為none時,元素永遠(yuǎn)不會成為鼠標(biāo)事件的目標(biāo),但是,當(dāng)其后代元素的pointer-events屬性指定其他值時,鼠標(biāo)事件可以指向后代元素,在這種情況下,鼠標(biāo)事件將在捕獲或冒泡階段觸發(fā)父元素的事件偵聽器。

$('.button').on('touchstart',function(){
  $('.upbox').hide();
  $('.underbox').hide();
  //馬上讓它不能點擊
  $('.underbox').css('pointer-events','none');
  //因為click事件需要300ms響應(yīng),所以我們時間定義360ms,時間一過又可以正常點擊了
  setTimeout(function(){$('.underbox').css('pointer-events','auto')},360);
});

   

   4.只用click

   頁面里的點擊事件都用click來觸發(fā),但是這樣的話,頁面里的點擊交互都將增加300ms延遲,想想都慢,但是如果交互性要求不高的話可以這么做,強(qiáng)烈不推薦 ,快一點總是好的。

 

   5.使用fastclick插件

   如果不介意多加載幾KB的話,可以使用fastclick庫,其實現(xiàn)思路是:取消 click 事件,用 touchend 模擬快速點擊行為,從此所有點擊事件都使用click,不會出現(xiàn)“穿透”的問題,并且沒有300ms的延遲。不建議使用,因為有人遇到了bug, fastclick 導(dǎo)致click事件觸發(fā)兩次的問題,而且開發(fā)者還必須先引入fastclick庫,再把頁面內(nèi)所有touch事件都換成click,稍微有點麻煩,而且多引入幾KB的文件只是為了解決點透問題不值當(dāng),不如用前三種方法中的任一種。

 

五、總結(jié)

   除了上面這五種辦法外,相信還有其他我本文中未收錄的方法,這就需要大家一起來探索了,其實遇到問題,第一重要的不是立即著手解決問題,而是找到問題的根源所在,之后針對根源去消滅問題,至于解決問題的方法,一千個人眼中一千個哈姆雷特,你喜歡哪種,就用那種方法來。

 

文章來源:“H5案例分享”團(tuán)隊原創(chuàng)文章

0 條評論

分享
公眾號
公眾號二維碼

? 2017 志進(jìn)科技 版權(quán)所有 上海志進(jìn)信息科技有限公司 備案號滬ICP備14017051號-2