(fastclick 소스 학습) 이벤트 최적화를 클릭, 모바일 터치를 종료

(fastclick 소스 학습) 이벤트 최적화를 클릭, 모바일 터치를 종료

최근에이 기록에 모바일 엔드 터치 앤 클릭 이벤트, 주위 fastclick 주요 콘텐츠가 공전의 학습 과정 최적화를 마이크로 채널 이동 끝 페이지의 일부를 수행.
fastclick GitHub의

의 기원

화면에 사용자가 클릭이 약 지연 이벤트 트리거 전에 클릭이 300ms됩니다 후 모바일 브라우저는 일반적으로 종료
- GOOGLE을

전화를 엽니 지연 데모를 보려면이 링크
(대부분의 브라우저가 fastclick github에 참조 존재하지 않는 문제를 연기했지만, 저자의 모바일 브라우저는 여전히 삼백 밀리 초 지연 문제가)
촬영은 다음이다
이미지 캡션

이 300ms가 지연 이유, 주요 두 번 클릭하여 줌 기능은 브라우저에서 더블 클릭으로 사용자가 클릭 확대할지 여부를 결정할 필요가있다. 이 문제가 해결되지
, 사용자 경험은 매우 특히 계산기로 현장에서 많이 사용하는 작업에, 부드럽게, 가난한 것, 한 문제가 해결되지 지연이 300ms, 나는 매우 느린 반응을 느낀다
이 질문에 관통 클릭

이벤트 트리거 순서

아이디어 fastclick 살펴보기 전에, 우리는 이벤트의 순서를 보면 트리거 무엇

  • touchstart
  • 하는 TouchMove
  • touchEnd
  • 마우스 오버 : 소자는 포인팅 장치 또는 서브 요소 청취자의 존재를 움직일 때, 마우스 오버 이벤트가 트리거된다.
  • mouseenter : 포인팅 장치 (보통 마우스) 요소에서 이동할 때, MouseMove 이벤트 이벤트가 트리거됩니다.
  • mousedown
  • 딸깍 하는 소리

모바일 최종 클릭 오, 터치 할 수없는,이 대기 시간 문제를이 300ms.

fastclick 아이디어

fastclick 아이디어는 유효한 탭 것으로 간주 경우 브라우저를 차단하면서, 다음, 이벤트 소스 (활성 트리거 클릭에 해당)에 배포 즉시 touchend시 클릭 이벤트를 시뮬레이션 터치 탭 (터치)의 사용을 시뮬레이션하는 것입니다 이 300ms 이후에 발생하는 클릭합니다.

소스 학습

매우 간단한 사용의 예를 살펴, 우리는 갈 첨부 함께 생각하고있다.

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

- Fastlick 라인에 몸에 직접 결합 -.
(:, 아이디어의 대부분은 의견 작성 부분의 개념의 이해에 영향을 미치지 않습니다 제거 다음과 같은 코드의 모든 주) 소스 코드의 구조를보기

//构造函数
    function FastClick(layer, options)
//判断是否需要浏览器原生的click事件(针对一些特殊元素比如表单)
    FastClick.prototype.needsClick = function(target)
//发送模拟的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 捕获阶段监听
    FastClick.prototype.onClick = function(event)
//销毁fastlick,移除事件绑定
    FastClick.prototype.destroy = function()
//绑定接口
    FastClick.attach = function(layer, options) {
        return new FastClick(layer, options);
    };

초기화 생성자의 실제 구현을 첨부, 우리는 생성자 무슨 일이 있었는지 살펴

    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实例
        for (var i = 0, l = methods.length; i < l; i++) {
            context[methods[i]] = bind(context[methods[i]], context);
        }
        //为当前fast click对象绑定的layer(我们的示例中时document.body)加监听
        layer.addEventListener('click', this.onClick, true);//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);
    }

주요 생성자는, 일부 속성, polyfill을 초기화하고 리스너를 추가하는 것입니다
의가 있는지 여부를 효과적으로 탭, 클릭 이벤트를 시뮬레이션하는 방법은 방법이 300ms 중지를 클릭 touchstart, touchend 결정하기 위해 메인 이벤트 인 방법을보고 시작하자
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).
    // 如果多触点可能是在缩放,不对targetElement初始化,在此提前终止避免误模拟产生click
    if (event.targetTouches.length > 1) {
      return true;
    }

    //获取发生事件源元素(目标阶段的元素)
    targetElement = this.getTargetElementFromEventTarget(event.target);
    touch = event.targetTouches[0];
    
    this.trackingClick = true;//标记开始跟踪click
    this.trackingClickStart = event.timeStamp;//开始跟踪时间
    this.targetElement = targetElement;//事件源元素

    //触摸坐标,接下来判断是否越界用到
    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
으로 다음을하는 TouchMove

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

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

    return true;
  };

범위 클릭 시뮬레이션 밖으로 슬라이딩하지 크게 슬라이드 탭 (swiper)와 호환 등 비교적 간단한하는 TouchMove
다음은 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;
    }
    //超时就不算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);//发送模拟click
    }

    return false;
  };
 //发送模拟的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分发模拟的click
    targetElement.dispatchEvent(clickEvent);
  };

마지막으로,도 청취 클릭 층의 무대를 캡처

  //click handler 捕获阶段监听
  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、出界会置为false,2成功模拟了一次完成tap并阻止click也会置为false,3、避免三方库影响
      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;
  };

 // 判断这次鼠标是否有效
  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;
    }

    // 标记fastclick模拟产生的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;
  };

이것은 (예를 무효로 한 후 캡처 및 버블 링 중지) 클릭이 유효 결정하기 위해 주로
기본 프로세스가 종료 된이 시점에서합니다.
노트에 지점을 가지고있는, 크롬의 저자 (버전 64.0.3282.119 (공식 빌드) (64 비트)) 테스트 한
인 stopPropagation는 stopImmediatePropagation 오 버블 링 또한 캡처 프로세스 방지를 중지뿐만 아닙니다.

최종적으로

소스 코드, 소스 코드를 읽기 권장, 초점에 많은 치료, 다른 브라우저 호환 및 특수 형태 요소가 fastclick의 GitHub의.
다음은 중국어와 코드 작성자가 댓글입니다 중국어 코드를 댓글을 달았습니다.
결함이있는 경우, 비판을 환영합니다.

참고

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

추천

출처www.cnblogs.com/jlfw/p/11914823.html