1、前言css
相信不少移動開發者都有這樣一個體會,那就是咱們在移動端點擊事件click對比touchend會有延遲,這是爲何呢?html
其實這是由於覽器在click後會等待約300ms去判斷用戶是否有雙擊行爲,手機須要知道用戶是否是想雙擊放大網頁內容。若是300ms內沒有再一次click,那麼就斷定這是一次單擊行爲,因此咱們基本上都用(touchstart/touchend),可是這些事件在執行完以後還會執行一次click事件。(至於具體的緣由這要從JS事件監聽機制的根本的講起,解釋起來太麻煩,感興趣的同窗能夠動手瞭解一下,咱們這裏就不作過多說明了)。ide
2、touch事件的來源網站
PC網頁上的大部分操做都是用鼠標的,即響應的是鼠標事件,包括mousedown、mouseup、mousemove和click事件。一次點擊行爲,事件的觸發過程爲:mousedown -> mouseup -> click 三步。插件
由於手機上沒有鼠標,因此就用觸摸事件touch去實現相似的功能。touch事件包含touchstart、touchmove、touchend,注意手機上並無tap事件。手指觸發觸摸事件的過程爲:touchstart -> touchmove -> touchend。htm
手機上沒有鼠標,但不表明手機不能響應mouse事件,實際上是藉助touch去觸發mouse事件。有人在PC和手機上對事件作了對比實驗,以說明手機對touch事件相應速度快於mouse事件。blog
從上面的圖表對比中咱們能夠看出在手機上,當咱們手觸碰屏幕時,要過300ms左右纔會觸發mousedown事件,因此click事件在手機上看起來就像慢半拍同樣。事件
3、點擊穿透的場景開發
點擊穿透的現象主要分爲四種:input
1.點擊蒙層(Mask Layer)上的關閉按鈕,蒙層消失後發現觸發了按鈕下面元素的click事件。
蒙層的關閉按鈕綁定的是touch事件,而按鈕下面元素綁定的是click事件,touch事件觸發以後,蒙層消失了,300ms後這個點的click事件出發,事件的目標元素天然就變成了按鈕下面的元素,由於按鈕跟蒙層一塊兒消失了。
2.若是按鈕下面剛好是一個有href屬性的a標籤,那麼頁面就會發生跳轉,由於a標籤跳轉默認是click事件觸發,因此穿透原理和上面的徹底相同。
3.若是按鈕下面剛好是文本框input或文本域textarea,則文本框或文本域就會獲取焦點,穿透原理和上面的相同。
4.此次沒有蒙層,直接點擊頁內按鈕跳轉至新頁,而後發現新頁面中對應位置元素的click事件被觸發了。
和蒙層的道理同樣,js控制頁面跳轉的邏輯若是是綁定在touch事件上的,並且新頁面中對應位置的元素綁定的是click事件,並且頁面在300ms內完成了跳轉,三個條件同時知足,就出現這種狀況了。
其餘的點擊穿透的例子還有不少,我就不一一細說了。
4、Touch穿透的解決辦法
1.延遲
蒙層被點擊後延時至少300ms再在完全隱藏掉蒙層顯示下層的內容,缺點是隱藏蒙層變慢了,350ms仍是能感受到慢的,可是這種方法只須要針對蒙層作處理就好了,改動很是小,若是要求不高的話,用這個比較省時省力。
2.增長中間蒙層
咱們還能夠動態地在觸摸位置生成一個透明的元素,這樣當上層元素消失而延遲的click來到時,它點擊到的是那個透明的元素,就不會「穿透」到下面去了,而後再在必定的延遲後將生成的透明元素移除。
3.利用pointer-events方法
pointer-events是CSS3中的屬性,它有不少取值,auto | none | visiblepainted | visiblefill | visiblestroke | visible | painted | fill | stroke | all,有用的主要是auto和none,其餘屬性值爲SVG服務。
當pointer-events取值爲auto時,效果與pointer-events屬性未指定時的表現效果相同;當取值爲none時,元素永遠不會成爲鼠標事件的目標,可是,當其後代元素的pointer-events屬性指定其餘值時,鼠標事件能夠指向後代元素,在這種狀況下,鼠標事件將在捕獲或冒泡階段觸發父元素的事件偵聽器。
<div class="upbox"></div> <div class="underbox"></div> <div class="button"></div> $('.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來觸發,可是這樣的話,頁面裏的點擊交互都將增長300ms延遲,想一想都慢,可是若是交互性要求不高的話能夠這麼作,強烈不推薦 ,快一點老是好的。
5.使用fastclick插件
若是不介意多加載幾KB的話,可使用fastclick庫,其實現思路是:取消 click 事件,用 touchend 模擬快速點擊行爲,今後全部點擊事件都使用click,不會出現「穿透」的問題,而且沒有300ms的延遲。不建議使用,由於有人遇到了bug, fastclick 致使click事件觸發兩次的問題,並且開發者還必須先引入fastclick庫,再把頁面內全部touch事件都換成click,稍微有點麻煩,並且多引入幾KB的文件只是爲了解決點透問題不值當,不如用前三種方法中的任一種。
5、總結
除了上面這五種辦法外,相信還有其餘我本文中未收錄的方法,這就須要你們一塊兒來探索了,其實遇到問題,第一重要的不是當即着手解決問題,而是找到問題的根源所在,以後針對根源去消滅問題,至於解決問題的方法,一千我的眼中一千個哈姆雷特,你喜歡哪一種,就用那種方法來。
此文章主要發佈在網站H5案例分享、公衆號H5握手和我的博客中,轉載請註明出處。