码迷,mamicode.com
首页 > 其他好文 > 详细

fastclick源码学习(1)

时间:2015-10-30 23:03:18      阅读:447      评论:0      收藏:0      [点我收藏+]

标签:

1、入口

1 FastClick.attach(document.body)

2、初始化参数

function FastClick(layer, options) {
        var oldOnClick;
        options = options || {};
        this.trackingClick = false;
        this.trackingClickStart = 0;
        this.targetElement = null;
        this.touchStartX = 0;
        this.touchStartY = 0;
        this.touchBoundary = options.touchBoundary || 10;

        this.layer = layer;

        this.tapDelay = options.tapDelay || 200;
        this.tapTimeout = options.tapTimeout || 700;

        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);
    }

初始化参数主要是设置touchBoundary、tapDelay、tapTimeout几个参数,用于后文鉴定一次点击是否是有效的click。另外初始化给layer绑定的touchstart、toustartend监听

3、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).
        if (event.targetTouches.length > 1) {
            return true;
        }
        targetElement = this.getTargetElementFromEventTarget(event.target);
        touch = event.targetTouches[0];

        if (deviceIsIOS) {
      //这里先不研究
        }

        this.trackingClick = true;
        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();
        }
        return true;
    };
View Code

touchstart貌似只是在做一些记录性工作,记录了用户点击时的坐标,应该是等待与离开屏幕是的坐标计算是否超过touchBoundary,超过则不认为是一次点击。

以及本次点击与上次点击的事件差,如果小于tapDelay,则event.preventDefalut()。这句话的作用待touchend时研究下

4、touchend

技术分享
 1 FastClick.prototype.onTouchEnd = function(event) {
 2         var forElement, trackingClickStart, targetTagName, scrollParent, touch, targetElement = this.targetElement;
 3 
 4         if (!this.trackingClick) {
 5             return true;
 6         }
 7 
 8         // Prevent phantom clicks on fast double-tap (issue #36)
 9         if ((event.timeStamp - this.lastClickTime) < this.tapDelay) {
10             this.cancelNextClick = true;
11             return true;
12         }
13 
14         if ((event.timeStamp - this.trackingClickStart) > this.tapTimeout) {
15             return true;
16         }
17 
18         // Reset to prevent wrong click cancel on input (issue #156).
19         this.cancelNextClick = false;
20 
21         this.lastClickTime = event.timeStamp;
22 
23         trackingClickStart = this.trackingClickStart;
24         this.trackingClick = false;
25         this.trackingClickStart = 0;
26 
27         // On some iOS devices, the targetElement supplied with the event is invalid if the layer
28         // is performing a transition or scroll, and has to be re-detected manually. Note that
29         // for this to function correctly, it must be called *after* the event target is checked!
30         // See issue #57; also filed as rdar://13048589 .
31         if (deviceIsIOSWithBadTarget) {
32             touch = event.changedTouches[0];
33 
34             // In certain cases arguments of elementFromPoint can be negative, so prevent setting targetElement to null
35             targetElement = document.elementFromPoint(touch.pageX - window.pageXOffset, touch.pageY - window.pageYOffset) || targetElement;
36             targetElement.fastClickScrollParent = this.targetElement.fastClickScrollParent;
37         }
38 
39         targetTagName = targetElement.tagName.toLowerCase();
40         if (targetTagName === ‘label‘) {
41             forElement = this.findControl(targetElement);
42             if (forElement) {
43                 this.focus(targetElement);
44                 if (deviceIsAndroid) {
45                     return false;
46                 }
47 
48                 targetElement = forElement;
49             }
50         } else if (this.needsFocus(targetElement)) {
51 
52             // Case 1: If the touch started a while ago (best guess is 100ms based on tests for issue #36) then focus will be triggered anyway. Return early and unset the target element reference so that the subsequent click will be allowed through.
53             // Case 2: Without this exception for input elements tapped when the document is contained in an iframe, then any inputted text won‘t be visible even though the value attribute is updated as the user types (issue #37).
54             if ((event.timeStamp - trackingClickStart) > 100 || (deviceIsIOS && window.top !== window && targetTagName === ‘input‘)) {
55                 this.targetElement = null;
56                 return false;
57             }
58 
59             this.focus(targetElement);
60             this.sendClick(targetElement, event);
61 
62             // Select elements need the event to go through on iOS 4, otherwise the selector menu won‘t open.
63             // Also this breaks opening selects when VoiceOver is active on iOS6, iOS7 (and possibly others)
64             if (!deviceIsIOS || targetTagName !== ‘select‘) {
65                 this.targetElement = null;
66                 event.preventDefault();
67             }
68 
69             return false;
70         }
71 
72         if (!this.needsClick(targetElement)) {
73             event.preventDefault();
74             this.sendClick(targetElement, event);
75         }
76 
77         return false;
78     };
View Code

touchend是fastclick的核心代码之一,首先判断本次点击是否有效(根据touchstart、touchend时间差,本次与上次的事件差)。

然后判断这个标签是否needFocus,若是,咋给点击的目标focus,并发送模拟点击事件。

技术分享
 1     FastClick.prototype.needsFocus = function(target) {
 2         switch (target.nodeName.toLowerCase()) {
 3         case ‘textarea‘:
 4             return true;
 5         case ‘select‘:
 6             return !deviceIsAndroid;
 7         case ‘input‘:
 8             switch (target.type) {
 9             case ‘button‘:
10             case ‘checkbox‘:
11             case ‘file‘:
12             case ‘image‘:
13             case ‘radio‘:
14             case ‘submit‘:
15                 return false;
16             }
View Code

意思是textarea、IOS下的select需要点击后处于激活状态,input[button, checkbox,file,image,radio,submit]不需要。默认也是不需要的

再判断点击目标是否需要原生click,若需要,则不发送模拟点击事件

技术分享
 1 FastClick.prototype.needsClick = function(target) {
 2         switch (target.nodeName.toLowerCase()) {
 3 
 4         // Don‘t send a synthetic click to disabled inputs (issue #62)
 5         case ‘button‘:
 6         case ‘select‘:
 7         case ‘textarea‘:
 8             if (target.disabled) {
 9                 return true;
10             }
11 
12             break;
13         case ‘input‘:
14 
15             // File inputs need real clicks on iOS 6 due to a browser bug (issue #68)
16             if ((deviceIsIOS && target.type === ‘file‘) || target.disabled) {
17                 return true;
18             }
19 
20             break;
21         case ‘label‘:
22         case ‘iframe‘: // iOS8 homescreen apps can prevent events bubbling into frames
23         case ‘video‘:
24             return true;
25         }
26 
27         return (/\bneedsclick\b/).test(target.className);
28     };
View Code

即disabled下的button select textarea,IOS下的file标签,label iframe video,即使使用fastclick.js也是收不到click事件的

5、sendClick

技术分享
 1     FastClick.prototype.sendClick = function(targetElement, event) {
 2         var clickEvent, touch;
 3 
 4         // On some Android devices activeElement needs to be blurred otherwise the synthetic click will have no effect (#24)
 5         if (document.activeElement && document.activeElement !== targetElement) {
 6             document.activeElement.blur();
 7         }
 8 
 9         touch = event.changedTouches[0];
10 
11         // Synthesise a click event, with an extra attribute so it can be tracked
12         clickEvent = document.createEvent(‘MouseEvents‘);
13         clickEvent.initMouseEvent(this.determineEventType(targetElement), true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
14         clickEvent.forwardedTouchEvent = true;
15         targetElement.dispatchEvent(clickEvent);
16     };
View Code

这是另一个核心函数,在touchend判断需要发送click事件的标签,通过这个标签发送click事件

fastclick源码学习(1)

标签:

原文地址:http://www.cnblogs.com/ward/p/4924572.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!