JS常用庫解密-FastClick

jopen 9年前發布 | 10K 次閱讀 FastClick JavaScript開發

 眾所周知,移動端在處理點擊事件的時候,會有300毫秒的延遲。恰恰是這300毫秒的延遲,會讓人有一種卡頓的體驗。

這300毫秒的原因,在于早期瀏覽器的實現中,瀏覽器不知道用戶觸摸后,到底想做什么,所以故意等待300毫秒,再觸發click事件。

既然我們已經知道了原因了,怎么解決呢?

方案1-粗暴治標法

因為瀏覽器對click事件的處理,有300ms的延遲,而touchstart幾乎是立即執行的,估將所有click事件的監聽,改為touchstart事件的監聽,即可消除這300ms的延遲。

但這樣副作用也很大,移動端的交互體驗全靠觸摸,touchstart將會干擾其他交互行為的處理,例如滾動、拖拽等。

方案2-模擬修復法

既然瀏覽器有這300ms的延遲,那么我們來代替瀏覽器判斷,手動觸發click事件,這也是fastClick的解決方案。

fastClick的核心代碼

FastClick.prototype.onTouchEnd = function(event){

  // 一些狀態監測代碼 

  // 從這里開始,
  if (!this.needsClick(targetElement)) {
    // 如果這不是一個需要使用原生click的元素,則屏蔽原生事件,避免觸發兩次click
    event.preventDefault(); 
    // 觸發一次模擬的click
    this.sendClick(targetElement, event);
  }
}

這里可以看到,FastClick在touchEnd的時候,在符合條件的情況下,主動觸發了click事件,這樣避免了瀏覽器默認的300毫秒等待判斷。為了防止原生的click被觸發,這里還通過event.preventDefault()屏蔽了原生的click事件。

我們來看看他是怎么模擬click事件的

FastClick.prototype.sendClick = function(targetElement, event) {

  // 這里是一些狀態檢查邏輯

  // 創建一個鼠標事件
  clickEvent = document.createEvent('MouseEvents');
  // 初始化鼠標事件為click事件
  clickEvent.initMouseEvent(this.determineEventType(targetElement), true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);

  // fastclick的內部變量,用來識別click事件是原生還是模擬
  clickEvent.forwardedTouchEvent = true;

  // 在目標元素上觸發該鼠標事件,
  targetElement.dispatchEvent(clickEvent);

我們在網上搜索fastClick,大部分都在說他解決了zepto的點擊穿透問題,他是怎么解決的呢?就是上面最后一句,他模擬的click事件是在touchEnd獲取的真實元素上觸發的,而不是通過坐標計算出來的元素。

最后,原理雖簡單,但還是建議大家直接用FastClick而不是自己再實現一個。因為,你看他源碼里面的注釋,有很多特殊情況的補丁的,自己實現一個精簡版難免會漏這漏那。

附錄

同步發表于 我的博客

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!