移動頁面click延遲引起的touch問題

1、事件捕獲與冒泡

先扯一下事件的觸發流程,這個以後會用到。android

DOM2級事件規定事件包括三個階段:git

① 事件捕獲階段github

② 處於目標階段chrome

③ 事件冒泡階段瀏覽器

大概的流程就是事件從最外層一層一層往裏面傳遞(捕獲階段), 到達觸發事件的目標元素(目標階段),而後再一層一層往上冒泡(冒泡階段)。這個流程事件所通過的元素綁定的對應事件的偵聽器都會被觸發。例如對元素p的子元素c綁定點擊事件,點擊元素c後會先在p觸發點擊事件,使用dispatch觸發也是。函數

PS:事件偵聽經過target.addEventListener(type, listener[, useCapture])添加,useCapture參數表明是否在捕獲階段觸發事件。 性能

2、click事件的300ms延遲

移動設備中使用click事件和在PC端會有所不一樣,大多數基於觸摸的瀏覽器設備,在點擊時都會有個300ms的事件觸發等待時間,緣由在於單擊後面還有個雙擊縮放動做,這個涉及到觸摸設備的手勢交互行爲原生設計,設備須要經過時間判斷是單擊仍是雙擊。spa

對於這300ms的延遲,根據網上搜索的資料,可經過幾個簡單的方法解決:firefox

  1. 無視之。。。若是所涉及業務對點擊的反應時間要求不大,300ms實際上是能夠忽略的。
  2. 在 chrome 和 firefox 的移動版本中,禁用頁面縮放可消除該延遲。不過只兼容這兩種很差。
  3. 在 chrome 32+ 中,設置 viewport 的寬度小於或等於物理設備的寬度。由於只支持chrome 32+,因此也忽略。
  4. IE10+中設置CSS觸摸 action 屬性。之後其餘瀏覽器可能也會支持。但目前只支持IE10+,因此也忽略。
  5. 使用touch事件而不是click事件。這樣必須能夠解決延遲,但也所以引起了奇怪的問題,由此轉入正文。

3、zepto的tap事件

若是咱們直接使用touchend事件來代替click事件,一個很明顯的不妥就是若是滑動到某個元素上放開手那麼就會觸發該元素的touchend事件,這明顯不跟點擊操做一致。另一個問題即觸發touchend事件後,在該區域300ms後還會觸發一次click事件,若是一個元素touchend後消失,那麼其點擊區域底下的元素還會被觸發一次click事件,這個問題叫作點透,不過這能夠經過event.preventDefault來阻止(默認行爲)。插件

爲了更好的模擬點擊事件並解決移動設備點擊的300ms延遲,zepto的touch模塊自定義了一個tap事件,該事件原理便是使用touch事件來模擬的。基本原理就是給元素綁定touchstart和touchend事件,而後判斷先後事件的觸發區域是否一致,是的話即觸發自定義的點擊事件。

看起來挺完美的,但事實上使用zepto的tap事件即便在事件回調函數中使用了preventDefault仍是會出現點透問題。究其緣由,就是zepto在觸發事件的時候使用了定時器。在自定義事件被觸發以前默認行爲早就發生了,所以阻止不了click事件的觸發。

    暫時無論zepto,對於click事件,咱們能夠用另一個插件提升click事件的響應速度,這就是fastclick!

4、fastclick

Fastclick的基本思想就是在某個父元素上捕獲其子元素的touchstart與touchend事件,而後依然根據位置信息判斷是否爲點擊動做,若是是的話當即使用dispatchEvent手動派發子元素的click事件,從而縮短了響應事件,而且在touchend的時候使用preventDefault阻止默認事件,防止300ms後再次觸發click事件。

事情貌似就這麼解決了,但事實就是沒這麼完美。撇開手動派發事件帶來的性能損耗不說,在android上preventDefault阻止touchend觸發click事件尚未用,即在android上只要使用了touchend,就必定會觸發click事件,翻閱了不少資料後發現這個問題沒法解決,有人說touchstart的時候調用preventDefault可阻止click,但親測過不行。

這時候,就只能用比較猥瑣的方法來解決了。在fastclick判斷爲點擊操做並觸發click事件時,咱們給事件對象添加一個flag。從以前的內容能夠得知click事件會先在外層容器上觸發,所以咱們在根目錄上偵聽click事件,當事件對象存在flag時即不作操做,當不存在時即阻止其事件派發流程。這樣即元素綁定在元素上的點擊事件偵聽器只會被手動觸發的click事件觸發。

document.addEventListener('click', function (event) {

         if (event.myclick == true) {

          return true;

         }

         if (event.stopImmediatePropagation) {

          event.stopImmediatePropagation();

         } else {

          event.propagationStopped = true;

         }

         event.stopPropagation();

         event.preventDefault();

         return true;

}, true);

 

雖然使用fastclick能夠解決click的延遲問題,但添加了許多額外的操做,性能上的損耗是無可避免的。所以若是對點擊操做的要求不是很高的話仍是建議忽略那點延遲。

相關文章
相關標籤/搜索