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

資訊專欄INFORMATION COLUMN

移動(dòng)端觸摸、點(diǎn)擊事件優(yōu)化(fastclick源碼學(xué)習(xí))

fxp / 1907人閱讀

摘要:移動(dòng)端觸摸點(diǎn)擊事件優(yōu)化源碼學(xué)習(xí)最近在做一些微信移動(dòng)端的頁(yè)面,在此記錄關(guān)于移動(dòng)端觸摸和點(diǎn)擊事件的學(xué)習(xí)優(yōu)化過(guò)程,主要內(nèi)容圍繞展開(kāi)。當(dāng)指針設(shè)備通常指鼠標(biāo)在元素上移動(dòng)時(shí)事件被觸發(fā)。移動(dòng)端有延遲問(wèn)題,可沒(méi)有哦。

移動(dòng)端觸摸、點(diǎn)擊事件優(yōu)化(fastclick源碼學(xué)習(xí))

最近在做一些微信移動(dòng)端的頁(yè)面,在此記錄關(guān)于移動(dòng)端觸摸和點(diǎn)擊事件的學(xué)習(xí)優(yōu)化過(guò)程,主要內(nèi)容圍繞fastclick展開(kāi)。
fastclick github

問(wèn)題起源
移動(dòng)端瀏覽器一般在用戶點(diǎn)擊屏幕之后會(huì)延遲大約300ms才觸發(fā)click event
——GOOGLE

手機(jī)打開(kāi)此鏈接查看延遲demo
(現(xiàn)在許多瀏覽器已經(jīng)不存在延遲問(wèn)題了,詳見(jiàn)fastclick github,但筆者的手機(jī)瀏覽器還是出現(xiàn)了三百毫秒延遲的問(wèn)題)
截圖如下

為什么會(huì)300ms延遲呢,主要是有一個(gè)雙擊縮放功能,瀏覽器需要判斷用戶點(diǎn)擊是否為雙擊縮放。這個(gè)問(wèn)題不解決,
1、用戶體驗(yàn)就會(huì)很差,很不流暢,尤其是在密集操作場(chǎng)景下,比如計(jì)算器,不解決300ms延遲問(wèn)題,感覺(jué)反應(yīng)很慢;
2、點(diǎn)擊穿透問(wèn)題

事件觸發(fā)順序

在了解fastclick的思路之前,我們先看一下事件觸發(fā)順序是怎樣的

touchstart

touchmove

touchend

mouseover :當(dāng)指針設(shè)備移動(dòng)到存在監(jiān)聽(tīng)器的元素或其子元素的時(shí)候,mouseover事件就會(huì)被觸發(fā)。

mouseenter:當(dāng)指針設(shè)備( 通常指鼠標(biāo) )在元素上移動(dòng)時(shí), mousemove 事件被觸發(fā)。

mousedown

click

移動(dòng)端click有300ms延遲問(wèn)題,touch可沒(méi)有哦。

fastclick思路

fastclick的思路就是利用touch來(lái)模擬tap(觸碰),如果認(rèn)為是一次有效的tap,則在touchend時(shí)立即模擬一個(gè)click事件,分發(fā)到事件源(相當(dāng)于主動(dòng)觸發(fā)一次click),同時(shí)阻止掉瀏覽器300ms后產(chǎn)生的click。

源碼學(xué)習(xí)

先看使用示例,很簡(jiǎn)單,我們的思路就一直跟著attach走。

if ("addEventListener" in document) {
    document.addEventListener("DOMContentLoaded", function() {
        FastClick.attach(document.body);
    }, false);
}

直接給body綁定fastlick就行了- -。
看源代碼結(jié)構(gòu)(注:以下所有代碼均去掉了一些不影響理解思路的部分,大部分思路寫(xiě)在注釋中)

//構(gòu)造函數(shù)
    function FastClick(layer, options)
//判斷是否需要瀏覽器原生的click事件(針對(duì)一些特殊元素比如表單)
    FastClick.prototype.needsClick = function(target)
//發(fā)送模擬的click event
    FastClick.prototype.sendClick = function(targetElement, event)
// touchstart eventhandler
    FastClick.prototype.onTouchStart = function(event)
// touchmove eventhandler
    FastClick.prototype.onTouchMove = function(event)
// touchend eventhandler
    FastClick.prototype.onTouchEnd = function(event)
// 判斷這次tap是否有效
    FastClick.prototype.onMouse = function(event) 
//click handler 捕獲階段監(jiān)聽(tīng)
    FastClick.prototype.onClick = function(event)
//銷毀fastlick,移除事件綁定
    FastClick.prototype.destroy = function()
//綁定接口
    FastClick.attach = function(layer, options) {
        return new FastClick(layer, options);
    };

attach實(shí)際就執(zhí)行了構(gòu)造函數(shù)進(jìn)行初始化,接下來(lái)我們來(lái)看構(gòu)造函數(shù)發(fā)生了什么

    function FastClick(layer,options){
        //一些屬性初始化
        //安卓一些老版本瀏覽器不支持bind, poly fill
        function bind (method, context) {
          return function () {
            return method.apply(context, arguments);
          };
        }
        var methods = ["onMouse", "onClick", "onTouchStart", "onTouchMove", 
        "onTouchEnd", "onTouchCancel"];
        var context = this;
        //將所有handler的this綁定到fastclick實(shí)例
        for (var i = 0, l = methods.length; i < l; i++) {
            context[methods[i]] = bind(context[methods[i]], context);
        }
        //為當(dāng)前fast click對(duì)象綁定的layer(我們的示例中時(shí)document.body)加監(jiān)聽(tīng)
        layer.addEventListener("click", this.onClick, true);//true 捕獲階段觸發(fā) 
        layer.addEventListener("touchstart", this.onTouchStart, false);
        layer.addEventListener("touchmove", this.onTouchMove, false);
        layer.addEventListener("touchend", this.onTouchEnd, false);
        layer.addEventListener("touchcancel", this.onTouchCancel, false);
    }

構(gòu)造函數(shù)主要是初始化一些屬性,polyfill,和添加監(jiān)聽(tīng),
下面開(kāi)始看一下重頭戲,touchstart,touchend是如何判斷tap是否有效、如何模擬click事件、如何阻止300ms后的click
touchstart

  FastClick.prototype.onTouchStart = function (event) {
    var targetElement, touch, selection;

    // Ignore multiple touches, otherwise pinch-to-zoom is prevented if both fingers are on the FastClick element (issue #111).
    // 如果多觸點(diǎn)可能是在縮放,不對(duì)targetElement初始化,在此提前終止避免誤模擬產(chǎn)生click
    if (event.targetTouches.length > 1) {
      return true;
    }

    //獲取發(fā)生事件源元素(目標(biāo)階段的元素)
    targetElement = this.getTargetElementFromEventTarget(event.target);
    touch = event.targetTouches[0];
    
    this.trackingClick = true;//標(biāo)記開(kāi)始跟蹤click
    this.trackingClickStart = event.timeStamp;//開(kāi)始跟蹤時(shí)間
    this.targetElement = targetElement;//事件源元素

    //觸摸坐標(biāo),接下來(lái)判斷是否越界用到
    this.touchStartX = touch.pageX;
    this.touchStartY = touch.pageY;

    // Prevent phantom clicks on fast double-tap (issue #36)
    if ((event.timeStamp - this.lastClickTime) < this.tapDelay) {
      event.preventDefault();//阻止之后的click
    }

    return true;
  };

touchstart主要是初始化跟蹤的tap相關(guān)的一些屬性,用于之后的判斷‘
接下來(lái)touchmove

 FastClick.prototype.onTouchMove = function (event) {
    if (!this.trackingClick) {
      return true;
    }

    // If the touch has moved, cancel the click tracking 移動(dòng)到了其他元素
    if (this.targetElement !== this.getTargetElementFromEventTarget(event.target) || this.touchHasMoved(event)) {//移動(dòng)越界了,取消本次click模擬處理,走原生流程
      this.trackingClick = false;
      this.targetElement = null;
    }

    return true;
  };

touchmove比較簡(jiǎn)單,主要是兼容滑動(dòng)tap(swiper)等等,滑動(dòng)越界則不模擬click
下面是touchend

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

    if (!this.trackingClick) {
      return true;
    }

    // Prevent phantom clicks on fast double-tap (issue #36)
    //阻止快速雙擊
    if ((event.timeStamp - this.lastClickTime) < this.tapDelay) {
      this.cancelNextClick = true;
      return true;
    }
    //超時(shí)就不算click了,走原生流程,不阻止click
    if ((event.timeStamp - this.trackingClickStart) > this.tapTimeout) {
      return true;
    }

    this.lastClickTime = event.timeStamp;

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



    // Prevent the actual click from going though - unless the target node is marked as requiring
    // real clicks or if it is in the whitelist in which case only non-programmatic clicks are permitted.
    if (!this.needsClick(targetElement)) {
      event.preventDefault();//阻止之后的click
      this.sendClick(targetElement, event);//發(fā)送模擬click
    }

    return false;
  };
 //發(fā)送模擬的click event
  FastClick.prototype.sendClick = function (targetElement, event) {
    var clickEvent, touch;

    // On some Android devices activeElement needs to be blurred otherwise the synthetic click will have no effect (#24)
    if (document.activeElement && document.activeElement !== targetElement) {
      document.activeElement.blur();
    }

    touch = event.changedTouches[0];

    //模擬click
    // Synthesise a click event, with an extra attribute so it can be tracked
    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;
    //向targetElement分發(fā)模擬的click
    targetElement.dispatchEvent(clickEvent);
  };

最后,還會(huì)在layer的click捕獲階段監(jiān)聽(tīng)

  //click handler 捕獲階段監(jiān)聽(tīng)
  FastClick.prototype.onClick = function (event) {
    var permitted;
    // It"s possible for another FastClick-like library delivered with third-party code to fire a click event before FastClick does (issue #44). In that case, set the click-tracking flag back to false and return early. This will cause onTouchEnd to return early.
    if (this.trackingClick) {//1、出界會(huì)置為false,2成功模擬了一次完成tap并阻止click也會(huì)置為false,3、避免三方庫(kù)影響
      this.targetElement = null;
      this.trackingClick = false;
      return true;
    }

    // Very odd behaviour on iOS (issue #18): if a submit element is present inside a form and the user hits enter in the iOS simulator or clicks the Go button on the pop-up OS keyboard the a kind of "fake" click event will be triggered with the submit-type input element as the target.
    if (event.target.type === "submit" && event.detail === 0) {
      return true;
    }

    permitted = this.onMouse(event);

    // Only unset targetElement if the click is not permitted. This will ensure that the check for !targetElement in onMouse fails and the browser"s click doesn"t go through.
    if (!permitted) {
      this.targetElement = null;
    }

    // If clicks are permitted, return true for the action to go through.
    return permitted;
  };

 // 判斷這次鼠標(biāo)是否有效
  FastClick.prototype.onMouse = function (event) {

    // If a target element was never set (because a touch event was never fired) allow the event
    if (!this.targetElement) {
      return true;
    }

    // 標(biāo)記fastclick模擬產(chǎn)生的event
    if (event.forwardedTouchEvent) {
      return true;
    }

    // Programmatically generated events targeting a specific element should be permitted
    if (!event.cancelable) {
      return true;
    }

    // Derive and check the target element to see whether the mouse event needs to be permitted;
    // unless explicitly enabled, prevent non-touch click events from triggering actions,
    // to prevent ghost/doubleclicks.
    // 是否需要原生的click
    if (!this.needsClick(this.targetElement) || this.cancelNextClick) {

      // Prevent any user-added listeners declared on FastClick element from being fired.
      if (event.stopImmediatePropagation) {
        event.stopImmediatePropagation();
      } else {

        // Part of the hack for browsers that don"t support Event#stopImmediatePropagation (e.g. Android 2)
        event.propagationStopped = true;
      }

      // Cancel the event 阻止事件捕獲和冒泡
      event.stopPropagation();
      event.preventDefault();

      return false;
    }

    // If the mouse event is permitted, return true for the action to go through.
    return true;
  };

這里主要是判斷這次click是否有效(如無(wú)效,則阻止捕獲和冒泡)
至此基本流程已經(jīng)結(jié)束。
其中有1個(gè)注意的點(diǎn),筆者在chrome(Version 64.0.3282.119 (Official Build) (64-bit))已測(cè)試
stopPropagation,stopImmediatePropagation不僅會(huì)阻止冒泡還會(huì)阻止捕獲過(guò)程哦。

最后

推薦閱讀源碼,源碼中有許多關(guān)于focus、不同瀏覽器兼容和特殊表單元素的處理fastclick github。
這里是筆者帶有中文注釋的代碼中文注釋代碼。
如有紕漏,歡迎批評(píng)指正。

Reference

MDN
https://juejin.im/entry/55d73...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/52463.html

相關(guān)文章

  • 移動(dòng)觸摸點(diǎn)擊事件優(yōu)化fastclick源碼學(xué)習(xí)

    摘要:移動(dòng)端觸摸點(diǎn)擊事件優(yōu)化源碼學(xué)習(xí)最近在做一些微信移動(dòng)端的頁(yè)面,在此記錄關(guān)于移動(dòng)端觸摸和點(diǎn)擊事件的學(xué)習(xí)優(yōu)化過(guò)程,主要內(nèi)容圍繞展開(kāi)。當(dāng)指針設(shè)備通常指鼠標(biāo)在元素上移動(dòng)時(shí)事件被觸發(fā)。移動(dòng)端有延遲問(wèn)題,可沒(méi)有哦。 移動(dòng)端觸摸、點(diǎn)擊事件優(yōu)化(fastclick源碼學(xué)習(xí)) 最近在做一些微信移動(dòng)端的頁(yè)面,在此記錄關(guān)于移動(dòng)端觸摸和點(diǎn)擊事件的學(xué)習(xí)優(yōu)化過(guò)程,主要內(nèi)容圍繞fastclick展開(kāi)。fastclic...

    paney129 評(píng)論0 收藏0
  • 移動(dòng)使用swiper+iscroll+fastClick:安卓觸摸swiper會(huì)觸發(fā)點(diǎn)擊事件

    摘要:難道是安卓上和執(zhí)行順序異于其他瀏覽器。因?yàn)槭褂昧艘院笫录兊脴O其敏感,所有的事件觸發(fā)之前,都會(huì)觸發(fā)。按照的邏輯,一旦觸發(fā)之后,所有的都被阻止冒泡,就會(huì)出現(xiàn)上面說(shuō)的問(wèn)題,解決方案如下圖增加上圖這個(gè)判定的即可。 這兩天做H5頁(yè)面,使用swiper+iscroll+fastClick,并沒(méi)有用swiper提供的tap和click事件,自己在元素上bind,因?yàn)榛卣{(diào)函數(shù)是統(tǒng)一處理,就沒(méi)用swi...

    KoreyLee 評(píng)論0 收藏0
  • zepto touch 庫(kù)源碼分析

    摘要:源碼分析不愿意下代碼的可以直接點(diǎn)這里地址首先贊一下的代碼注釋,非常全。屬性一個(gè)對(duì)象,包含了代表所有從上一次觸摸事件到此次事件過(guò)程中,狀態(tài)發(fā)生了改變的觸點(diǎn)的對(duì)象。 所謂 zepto 的 touch 其實(shí)就是指這個(gè)文件啦,可以看到區(qū)區(qū) 165 行(包括注釋)就完成了 swipe 和 tap 相關(guān)的事件實(shí)現(xiàn)。在正式開(kāi)始分析源碼之前,我們先說(shuō)說(shuō) touch 相關(guān)的幾個(gè)事件,因?yàn)闊o(wú)論是 tap ...

    lentrue 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<