国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

zepto touch 庫源碼分析

lentrue / 1016人閱讀

摘要:源碼分析不愿意下代碼的可以直接點這里地址首先贊一下的代碼注釋,非常全。屬性一個對象,包含了代表所有從上一次觸摸事件到此次事件過程中,狀態發生了改變的觸點的對象。

所謂 zepto 的 touch 其實就是指這個文件啦,可以看到區區 165 行(包括注釋)就完成了 swipe 和 tap 相關的事件實現。在正式開始分析源碼之前,我們先說說 touch 相關的幾個事件,因為無論是 tap 還是 swipe 都是基于他們的。

touch 相關事件

touchstart 觸摸屏幕的瞬間

touchmove 手指在屏幕上的移動過程一直觸發

touchend 離開屏幕的瞬間

touchcancel 觸摸取消(取決于瀏覽器實現,并不常用)

觸摸屏下事件觸發順序是

touchstart -> touchmove -> touchend -> click
引入 touch 的背景

click事件在移動端上會有 300ms 的延遲,同時因為需要 長按,雙觸擊 等富交互,所以我們通常都會引入類似 zepto 這樣的庫。zepto 實現了"swipe", "swipeLeft", "swipeRight", "swipeUp", "swipeDown", "doubleTap", "tap", "singleTap", "longTap" 這樣一些功能。

zepto touch 源碼

我們直接看到 touch 源碼的 49 行,從這里開始就是上述事件的實現了。不難想到 MSGesture 是對 mobile ie 的實現,本文不做討論。往下面看到 66 行,$(document).on("touchstart MSPointerDown pointerdown") 開始。

//判斷事件類型是否為 touch
if((_isPointerType = isPointerEventType(e, "down")) &&
  !isPrimaryTouch(e)) return
// touches 是觸摸點的數量
firstTouch = _isPointerType ? e : e.touches[0]
if (e.touches && e.touches.length === 1 && touch.x2) {
  touch.x2 = undefined
  touch.y2 = undefined
}
// 記錄第一次觸摸的時間
now = Date.now()
// 計算本次觸摸與最后一次的時間差
delta = now - (touch.last || now)
// 查找 touch 事件的 dom 
touch.el = $("tagName" in firstTouch.target ?
  firstTouch.target : firstTouch.target.parentNode)
// 如果 touchTimeout 存在就清理掉
touchTimeout && clearTimeout(touchTimeout)
// 記錄當前坐標
touch.x1 = firstTouch.pageX
touch.y1 = firstTouch.pageY
// 觸摸時間差小于 250ms 則為 DoubleTap
if (delta > 0 && delta <= 250) touch.isDoubleTap = true
// 記錄執行后的時間
touch.last = now
// 留一個長觸摸,如果 touchmove 會把這個清理掉
longTapTimeout = setTimeout(longTap, longTapDelay)  

接下來是 $(document).on("touchmove MSPointerMove pointermove")

//判斷事件類型是否為 move
if((_isPointerType = isPointerEventType(e, "move")) &&
          !isPrimaryTouch(e)) return
firstTouch = _isPointerType ? e : e.touches[0]
// 一旦進入 move 就會清理掉 LongTap
cancelLongTap()
// 當前手指坐標
touch.x2 = firstTouch.pageX
touch.y2 = firstTouch.pageY
// x 軸和 y 軸的變化量 Math.abs 是取絕對值的意思
deltaX += Math.abs(touch.x1 - touch.x2)
deltaY += Math.abs(touch.y1 - touch.y2)

最后當然就是 $(document).on("touchend MSPointerUp pointerup") 了,這個也是整個 touch 最為復雜的一部分。

if((_isPointerType = isPointerEventType(e, "up")) &&
          !isPrimaryTouch(e)) return
        cancelLongTap()

    // 如果是 swipe,x 軸或者 y 軸移動超過 30px
    if ((touch.x2 && Math.abs(touch.x1 - touch.x2) > 30) ||
        (touch.y2 && Math.abs(touch.y1 - touch.y2) > 30))

      swipeTimeout = setTimeout(function() {
        touch.el.trigger("swipe")
        // swipeDirection 是判斷 swipe 方向的
        touch.el.trigger("swipe" + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2)))
        touch = {}
      }, 0)

    // tap 事件
    else if ("last" in touch)
      if (deltaX < 30 && deltaY < 30) {
         // tapTimeout 是為了 scroll 的時候方便清除
        tapTimeout = setTimeout(function() {
          // 創建 tap 事件,并增加 cancelTouch 方法
          var event = $.Event("tap")
          event.cancelTouch = cancelAll
          touch.el.trigger(event)

          // 觸發 DoubleTap
          if (touch.isDoubleTap) {
            if (touch.el) touch.el.trigger("doubleTap")
            touch = {}
          }

          // singleTap (這個概念是相對于 DoubleTap 的,可以看看我們在最初的那段源碼解析中有這樣一段 if (delta > 0 && delta <= 250) touch.isDoubleTap = true ,所以 250 ms 之后沒有二次觸摸的就算是 singleTap 了 
          else {
            touchTimeout = setTimeout(function(){
              touchTimeout = null
              if (touch.el) touch.el.trigger("singleTap")
              touch = {}
            }, 250)
          }
        }, 0)
      } else {
        touch = {}
      }
      deltaX = deltaY = 0

整個讀下來其實就是對 touchstart, touchmove, touchend 做了一些封裝和判斷,然后通過 zepto 自己的事件體系來注冊和觸發。

fastclick 對比 zepto

我們在聊到移動端 js 方案的時候很容易聽到這兩者,但我個人認為這兩者是無法對比的。原因如下:zepto 是一個移動端的 js 庫,而 fastclick 專注于 click 在移動端的觸發問題。fastclick 的 github 主頁上有一句話是“Polyfill to remove click delays on browsers with touch UIs”,翻譯過來就是干掉移動端 click 延時的補丁。這個延時就是我們在引入 touch 的背景里提到過。

fastclick 源碼分析

不愿意下代碼的可以直接點這里github地址首先贊一下 fastclick 的代碼注釋,非常全。

fastclick 的使用非常簡單,直接 FastClick.attach(document.body); 一句話搞定。所以源碼分析就從 attach 方法來看吧,824 行

    FastClick.attach = function(layer, options) {
        // 返回 FastClick 實例 layer 是一個 element 通常是 document.body ,options 自然就是配置了
        return new FastClick(layer, options);
    };

接下來回到 23 行看到 FastClick 構造函數,

 // 方法綁定,兼容老版本的安卓
function bind(method, context) {
    return function() { return method.apply(context, arguments); };
}

var methods = ["onMouse", "onClick", "onTouchStart", "onTouchMove", "onTouchEnd", "onTouchCancel"];
var context = this;
for (var i = 0, l = methods.length; i < l; i++) {
    context[methods[i]] = bind(context[methods[i]], context);
}
 // 事件處理綁定部分
if (deviceIsAndroid) {
    layer.addEventListener("mouseover", this.onMouse, true);
    layer.addEventListener("mousedown", this.onMouse, true);
    layer.addEventListener("mouseup", this.onMouse, true);
}

layer.addEventListener("click", this.onClick, true);
layer.addEventListener("touchstart", this.onTouchStart, false);
layer.addEventListener("touchmove", this.onTouchMove, false);
layer.addEventListener("touchend", this.onTouchEnd, false);
layer.addEventListener("touchcancel", this.onTouchCancel, false);

 // stopImmediatePropagation 的兼容
 
 if (!Event.prototype.stopImmediatePropagation) {
    layer.removeEventListener = function(type, callback, capture) {
        var rmv = Node.prototype.removeEventListener;
        if (type === "click") {
            rmv.call(layer, type, callback.hijacked || callback, capture);
        } else {
            rmv.call(layer, type, callback, capture);
        }
    };

    layer.addEventListener = function(type, callback, capture) {
        var adv = Node.prototype.addEventListener;
        if (type === "click") {
            adv.call(layer, type, callback.hijacked || (callback.hijacked = function(event) {
                if (!event.propagationStopped) {
                    callback(event);
                }
            }), capture);
        } else {
            adv.call(layer, type, callback, capture);
        }
    };
}

// 如果 layer 有 onclick ,就把 onclick 轉換為 addEventListener 的方式
if (typeof layer.onclick === "function") {
    oldOnClick = layer.onclick;
    layer.addEventListener("click", function(event) {
        oldOnClick(event);
    }, false);
    layer.onclick = null;
}

FastClick.prototype.onTouchStart 和 zepto 一樣做了一些參數的紀錄,所以我這里就直接跳到 FastClick.prototype.onTouchEnd 看 fastclick 的核心。

FastClick.prototype.onTouchEnd = function(event) {
    var forElement, trackingClickStart, targetTagName, scrollParent, touch, targetElement = this.targetElement;

    if (!this.trackingClick) {
        return true;
    }
    // 防止 double tap 的時間間隔內 click 觸發
    if ((event.timeStamp - this.lastClickTime) < this.tapDelay) {
        this.cancelNextClick = true;
        return true;
    }
    // 超出 longtap 的時間
    if ((event.timeStamp - this.trackingClickStart) > this.tapTimeout) {
        return true;
    }

    this.cancelNextClick = false;
    // 紀錄當前時間
    this.lastClickTime = event.timeStamp;

    trackingClickStart = this.trackingClickStart;
    this.trackingClick = false;
    this.trackingClickStart = 0;

    if (deviceIsIOSWithBadTarget) {
        touch = event.changedTouches[0];
        targetElement = document.elementFromPoint(touch.pageX - window.pageXOffset, touch.pageY - window.pageYOffset) || targetElement;
        targetElement.fastClickScrollParent = this.targetElement.fastClickScrollParent;
    }
    // 獲取 targetTagName 上面的一段是 targetTagName 兼容性
    targetTagName = targetElement.tagName.toLowerCase();
    // 解決 label for
    if (targetTagName === "label") {
        forElement = this.findControl(targetElement);
        if (forElement) {
            this.focus(targetElement);
            if (deviceIsAndroid) {
                return false;
            }

            targetElement = forElement;
        }
    } else if (this.needsFocus(targetElement)) {
        if ((event.timeStamp - trackingClickStart) > 100 || (deviceIsIOS && window.top !== window && targetTagName === "input")) {
            this.targetElement = null;
            return false;
        }
        // 解決 input focus 
        this.focus(targetElement);
        // 觸發 sendClick
        this.sendClick(targetElement, event);

        if (!deviceIsIOS || targetTagName !== "select") {
            this.targetElement = null;
            event.preventDefault();
        }

        return false;
    }

    if (deviceIsIOS && !deviceIsIOS4) {
        scrollParent = targetElement.fastClickScrollParent;
        if (scrollParent && scrollParent.fastClickLastScrollTop !== scrollParent.scrollTop) {
            return true;
        }
    }
    // 最后就來觸發 sendClick 了
    if (!this.needsClick(targetElement)) {
        event.preventDefault();
        this.sendClick(targetElement, event);
    }

    return false;
};

看完上面的代碼,我們馬上來解讀 FastClick.prototype.sendClick

FastClick.prototype.sendClick = function(targetElement, event) {
    var clickEvent, touch;
    // 拿觸摸的第一個手指
    touch = event.changedTouches[0];
    // 自定義 clickEvent 事件
    clickEvent = document.createEvent("MouseEvents");
    clickEvent.initMouseEvent(this.determineEventType(targetElement), true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
    clickEvent.forwardedTouchEvent = true;
    // 觸發 clickEvent 事件
    targetElement.dispatchEvent(clickEvent);
};

到此 fastclick 主要的東西我們就看得差不多了,代碼當中不難看到 fastclick 的兼容性做的很好。它的主要目的是解決 click 在觸摸屏下的使用,引入之后再初始化一次就好了,很適合復用代碼的情景。

擴展講一下 touchEvent

本文中 zepto 和 fastclick 都有用到 touchEvent,但是 zepto 當中用的是 e.touches 而 fastclick 卻用的是 e.targetTouches。這兩者的差異我們來一點一點地扒。

TouchEvent 是一類描述手指在觸摸平面(觸摸屏、觸摸板等)的狀態變化的事件。這類事件用于描述一個或多個觸點,使開發者可以檢測觸點的移動,觸點的增加和減少,等等。

屬性:

TouchEvent.changedTouches 一個 TouchList 對象,包含了代表所有從上一次觸摸事件到此次事件過程中,狀態發生了改變的觸點的 Touch 對象。

TouchEvent.targetTouches 一個 TouchList 對象,是包含了如下觸點的 Touch 對象:觸摸起始于當前事件的目標 element 上,并且仍然沒有離開觸摸平面的觸點.

TouchEvent.touches 一個 TouchList 對象,包含了所有當前接觸觸摸平面的觸點的 Touch 對象,無論它們的起始于哪個 element 上,也無論它們狀態是否發生了變化。

TouchEvent.type 此次觸摸事件的類型,可能值為 touchstart, touchmove, touchend 等等

TouchEvent.target 觸摸事件的目標 element,這個目標元素對應 TouchEvent.changedTouches 中的觸點的起始元素。

TouchEvent.altKey, TouchEvent.ctrlKey, TouchEvent.metaKey, TouchEvent.shiftKey 觸摸事件觸發時,鍵盤對應的鍵(例如 alt )是否被按下。

TouchList 與 Touch

TouchList 就是一系列的 Touch,通過 TouchList.length 可以知道當前有幾個觸點,TouchList[0] 或者 TouchList.item(0) 用來訪問第一個觸點。

屬性

Touch.identifier:touch 的唯一標志,整個 touch 過程中(也就是 end 之前)不會改變

Touch.screenXTouch.screenY:坐標原點為屏幕左上角

Touch.clientXTouch.clientY:坐標原點在當前可視區域左上角,這兩個值不包含滾動偏移

Touch.pageXTouch.pageY:坐標原點在HTML文檔左上角,這兩個值包含了水平滾動的偏移

Touch.radiusXTouch.radiusY:觸摸平面的最小橢圓的水平軸(X軸)半徑和垂直軸(Y軸)半徑

Touch.rotationAngle:觸摸平面的最小橢圓與水平軸順時針夾角

Touch.force:壓力值 0.0-1.0

Touch.target:Touch相關事件觸發時的 element 不會隨 move 變化。如果 move 當中該元素被刪掉,這個 target 依然會不變,但不會冒泡。最佳實踐是將觸摸事件的監聽器綁定到這個元素本身, 防止元素被移除后, 無法再從它的上一級元素上偵測到從該元素冒泡的事件。

希望本文能解答一些大家在移動端開發當中的一些問題,本文行文匆忙如有不正確的地方希望能回復告知。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/79895.html

相關文章

  • Zepto源碼Touch模塊

    摘要:在觸發事件前,先將保存定時器的變量釋放,如果對象中存在,則觸發事件,保存的是最后觸摸的時間。如果有觸發的定時器,清除定時器即可阻止事件的觸發。其實就是清除所有相關的定時器,最后將對象設置為。進入時,立刻清除定時器的執行。 大家都知道,因為歷史原因,移動端上的點擊事件會有 300ms 左右的延遲,Zepto 的 touch 模塊解決的就是移動端點擊延遲的問題,同時也提供了滑動的 swip...

    Prasanta 評論0 收藏0
  • Zepto源碼之Gesture模塊

    摘要:模塊基于上的事件的封裝,利用屬性,封裝出系列事件。這個判斷需要引入設備偵測模塊。然后是監測事件,根據這三個事件,可以組合出和事件。其中變量對象和模塊中的對象的作用差不多,可以先看看讀源碼之模塊對模塊的分析。 Gesture 模塊基于 IOS 上的 Gesture 事件的封裝,利用 scale 屬性,封裝出 pinch 系列事件。 讀 Zepto 源碼系列文章已經放到了github上,歡...

    coolpail 評論0 收藏0
  • FastClick 源碼解讀

    摘要:所有瀏覽器瀏覽器不支持安卓中中有屬性安卓中中有屬性有屬性的有屬性的所以在不需要的瀏覽器會直接掉,不會執行下面的所有代碼。見源碼行,可以看出在響應無操作后,則觸發。 其實一直就想花些時間讀一讀那些優秀的開源庫,今天終于下了決定打算死磕下自己,2016年每個月讀2-3個優秀的開源庫,把源碼精彩的地方和自己心得分享給大家。 目錄 (一)背景(二)源碼解析(三)Zepto 點擊穿透與 Fast...

    Chaz 評論0 收藏0
  • 如何實現swipe、tap、longTap等自定義事件

    摘要:分別存儲事件的定時器。事件定時器延時時間存儲事件對象滑動方向判斷我們根據下圖以及對應的代碼來理解滑動的時候方向是如何判定的。取消長按,以及取消所有事件取消長按取消所有事件方式都是類似,先調用取消定時器,然后釋放對應的變量,等候垃圾回收。 前言 移動端原生支持touchstart、touchmove、touchend等事件,但是在平常業務中我們經常需要使用swipe、tap、double...

    羅志環 評論0 收藏0

發表評論

0條評論

lentrue

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<