fastclick源码学习(1)

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

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

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             }

意思是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     };

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

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

时间: 2024-08-04 16:04:15

fastclick源码学习(1)的相关文章

iscroll源码学习(1)

iscroll是移端端开发的两大利器之一(另一个是fastclick),为了将它整合的avalon,需要对它认真学习一番.下面是我的笔记. 第一天看的是它的工具类util.js //用于做函数节流 var rAF = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || win

【iScroll源码学习02】分解iScroll三个核心事件点

前言 最近两天看到很多的总结性发言,我想想今年好像我的变化挺大的,是不是该晚上来水一发呢?嗯,决定了,晚上来水一发! 上周六,我们简单模拟了下iScroll的实现,周日我们开始了学习iScroll的源码,今天我们接着上次的记录学习,因为最近事情稍微有点多了 学习进度可能要放慢,而且iScroll这个库实际意义很大,不能囫囵吞枣的学习,要学到精华,并且要用于项目中的,所以初步规划是最近两周主要围绕iScroll展开 而后两个选择:① 分离iScroll代码用于项目:② 抄袭iScroll精华部分用

FireMonkey 源码学习(5)

(5)UpdateCharRec 该函数的源码分析如下: procedure TTextLayoutNG.UpdateCharRec(const ACanvas: TCanvas; NeedBitmap: Boolean; var NewRec: PCharRec; HasItem: Boolean; const CharDic: TCharDic; const AFont: TFont; const Ch: UCS4Char; const NeedPath: Boolean = False);

jquery源码学习

jQuery 源码学习是对js的能力提升很有帮助的一个方法,废话不说,我们来开始学习啦 我们学习的源码是jquery-2.0.3已经不支持IE6,7,8了,因为可以少学很多hack和兼容的方法. jquery-2.0.3的代码结构如下 首先最外层为一个闭包, 代码执行的最后一句为window.$ = window.jquery = jquery 让闭包中的变量暴露倒全局中. 传参传入window是为了便于压缩 传入undefined是为了undifined被修改,他是window的属性,可以被修

Hadoop源码学习笔记(1) ——第二季开始——找到Main函数及读一读Configure类

Hadoop源码学习笔记(1) ——找到Main函数及读一读Configure类 前面在第一季中,我们简单地研究了下Hadoop是什么,怎么用.在这开源的大牛作品的诱惑下,接下来我们要研究一下它是如何实现的. 提前申明,本人是一直搞.net的,对java略为生疏,所以在学习该作品时,会时不时插入对java的学习,到时也会摆一些上来,包括一下设计模式之类的.欢迎高手指正. 整个学习过程,我们主要通过eclipse来学习,之前已经讲过如何在eclipse中搭建调试环境,这里就不多述了. 在之前源码初

HSQLDB源码学习——数据库安装启动及JDBC连接

HSQLDB 是一个轻量级的纯Java开发的开放源代码的关系数据库系统.因为HSQLDB的轻量(占用空间小),使用简单,支持内存运行方式等特点,HSQLDB被广泛用于开发环境和某些中小型系统中. 在http://sourceforge.net/projects/hsqldb/files/下载了HSQLDB 1.8.0版本.把下载的zip文件解压缩至任意目录例如c:\hsqldb1.8便完成安装. hsqldb有四种运行模式: 一.内存(Memory-Only)模式:所有数据都在内存里操作.应用程

lodash源码学习(10)

_.delay(func, wait, [args]) 延迟wait毫秒之后调用该函数,添加的参数为函数调用时的参数 //delay.js var baseDelay = require('./_baseDelay'),//baseDelay方法 baseRest = require('./_baseRest'),//创建使用rest参数方法 toNumber = require('./toNumber');//转化为数字 /** * * @param {Function} func 需要延迟执

lodash源码学习(2)

继续学习lodash,依然是数组的方法 “Array” Methods _.indexOf(array, value, [fromIndex=0]) 获取value在数组 array所在的索引值 使用 SameValueZero方式比较(第一个全等===的元素). 如果 fromIndex 值是负数, 则从array末尾起算 该方法依赖于strictIndexOf和baseIndexOf方法,先看它们的源码 //_strictIndexOf.js /** * _.indexOf的专业版本,对元素

jQuery源码学习感想

还记得去年(2015)九月份的时候,作为一个大四的学生去参加美团霸面,结果被美团技术总监教育了一番,那次问了我很多jQuery源码的知识点,以前虽然喜欢研究框架,但水平还不足够来研究jQuery源码,那时我不明白他们为何要求那么高,现在才知道,原来没那么高,他问的都是jQuery最基本的框架架构,不过对于不知道的来说,再简单我也是不知道,那时写了一篇博文去吐槽了一下,那时候也是我自己真正激发自己的时候,那时候我说我一定要搞好自己的jQuery基础,没想到那么快就实现了,一个月的源码学习时间就结束