收藏 | 點贊
一、前言
相信很多移動開發(fā)者都有這樣一個體會,那就是我們在移動端點擊事件click對比touchend會有延遲,這是為什么呢?
其實這是因為覽器在click后會等待約300ms去判斷用戶是否有雙擊行為,手機需要知道用戶是不是想雙擊放大網(wǎng)頁內(nèi)容。如果300ms內(nèi)沒有再一次click,那么就判定這是一次單擊行為,所以我們基本上都用(touchstart/touchend),但是這些事件在執(zhí)行完之后還會執(zhí)行一次click事件。(至于具體的原因這要從JS事件監(jiān)聽機制的根本的講起,解釋起來太麻煩,感興趣的同學可以動手了解一下,我們這里就不做過多說明了)。
二、touch事件的來源
PC網(wǎng)頁上的大部分操作都是用鼠標的,即響應的是鼠標事件,包括mousedown、mouseup、mousemove和click事件。一次點擊行為,事件的觸發(fā)過程為:mousedown -> mouseup -> click 三步。
因為手機上沒有鼠標,所以就用觸摸事件touch去實現(xiàn)類似的功能。touch事件包含touchstart、touchmove、touchend,注意手機上并沒有tap事件。手指觸發(fā)觸摸事件的過程為:touchstart -> touchmove -> touchend。
手機上沒有鼠標,但不代表手機不能響應mouse事件,其實是借助touch去觸發(fā)mouse事件。有人在PC和手機上對事件做了對比實驗,以說明手機對touch事件相應速度快于mouse事件。
從上面的圖表對比中我們可以看出在手機上,當我們手觸碰屏幕時,要過300ms左右才會觸發(fā)mousedown事件,所以click事件在手機上看起來就像慢半拍一樣。
三、點擊穿透的場景
點擊穿透的現(xiàn)象主要分為四種:
1.點擊蒙層(Mask Layer)上的關(guān)閉按鈕,蒙層消失后發(fā)現(xiàn)觸發(fā)了按鈕下面元素的click事件。
蒙層的關(guān)閉按鈕綁定的是touch事件,而按鈕下面元素綁定的是click事件,touch事件觸發(fā)之后,蒙層消失了,300ms后這個點的click事件出發(fā),事件的目標元素自然就變成了按鈕下面的元素,因為按鈕跟蒙層一起消失了。
2.如果按鈕下面恰好是一個有href屬性的a標簽,那么頁面就會發(fā)生跳轉(zhuǎn),因為a標簽跳轉(zhuǎn)默認是click事件觸發(fā),所以穿透原理和上面的完全相同。
3.如果按鈕下面恰好是文本框input或文本域textarea,則文本框或文本域就會獲取焦點,穿透原理和上面的相同。
4.這次沒有蒙層,直接點擊頁內(nèi)按鈕跳轉(zhuǎn)至新頁,然后發(fā)現(xiàn)新頁面中對應位置元素的click事件被觸發(fā)了。
和蒙層的道理一樣,js控制頁面跳轉(zhuǎn)的邏輯如果是綁定在touch事件上的,而且新頁面中對應位置的元素綁定的是click事件,而且頁面在300ms內(nèi)完成了跳轉(zhuǎn),三個條件同時滿足,就出現(xiàn)這種情況了。
其他的點擊穿透的例子還有很多,我就不一一細說了。
四、Touch穿透的解決辦法
1.延遲
蒙層被點擊后延時至少300ms再在徹底隱藏掉蒙層顯示下層的內(nèi)容,缺點是隱藏蒙層變慢了,350ms還是能感覺到慢的,但是這種方法只需要針對蒙層做處理就行了,改動非常小,如果要求不高的話,用這個比較省時省力。
2.增加中間蒙層
我們還可以動態(tài)地在觸摸位置生成一個透明的元素,這樣當上層元素消失而延遲的click來到時,它點擊到的是那個透明的元素,就不會“穿透”到下面去了,然后再在一定的延遲后將生成的透明元素移除。
3.利用pointer-events方法
pointer-events是CSS3中的屬性,它有很多取值,auto | none | visiblepainted | visiblefill | visiblestroke | visible | painted | fill | stroke | all,有用的主要是auto和none,其他屬性值為SVG服務(wù)。
當pointer-events取值為auto時,效果與pointer-events屬性未指定時的表現(xiàn)效果相同;當取值為none時,元素永遠不會成為鼠標事件的目標,但是,當其后代元素的pointer-events屬性指定其他值時,鼠標事件可以指向后代元素,在這種情況下,鼠標事件將在捕獲或冒泡階段觸發(fā)父元素的事件偵聽器。
$('.button').on('touchstart',function(){ $('.upbox').hide(); $('.underbox').hide(); //馬上讓它不能點擊 $('.underbox').css('pointer-events','none'); //因為click事件需要300ms響應,所以我們時間定義360ms,時間一過又可以正常點擊了 setTimeout(function(){$('.underbox').css('pointer-events','auto')},360); });
4.只用click
頁面里的點擊事件都用click來觸發(fā),但是這樣的話,頁面里的點擊交互都將增加300ms延遲,想想都慢,但是如果交互性要求不高的話可以這么做,強烈不推薦 ,快一點總是好的。
5.使用fastclick插件
如果不介意多加載幾KB的話,可以使用fastclick庫,其實現(xiàn)思路是:取消 click 事件,用 touchend 模擬快速點擊行為,從此所有點擊事件都使用click,不會出現(xiàn)“穿透”的問題,并且沒有300ms的延遲。不建議使用,因為有人遇到了bug, fastclick 導致click事件觸發(fā)兩次的問題,而且開發(fā)者還必須先引入fastclick庫,再把頁面內(nèi)所有touch事件都換成click,稍微有點麻煩,而且多引入幾KB的文件只是為了解決點透問題不值當,不如用前三種方法中的任一種。
五、總結(jié)
除了上面這五種辦法外,相信還有其他我本文中未收錄的方法,這就需要大家一起來探索了,其實遇到問題,第一重要的不是立即著手解決問題,而是找到問題的根源所在,之后針對根源去消滅問題,至于解決問題的方法,一千個人眼中一千個哈姆雷特,你喜歡哪種,就用那種方法來。
文章來源:“H5案例分享”團隊原創(chuàng)文章
0 條評論