深入解析FastClick解决延迟点击
来源:互联网 发布:财汇金融大数据终端 编辑:程序博客网 时间:2024/06/06 02:11
下载
源码和文档gitHub上都有,有兴趣的可以去逛逛 https://github.com/ftlabs/fastclick
使用
<script src="./js/fastclick.js"></script><script> window.addEventListener( "load", function() { FastClick.attach( document.body ); }, false );</script>
源码解析
attach方法:
FastClick.attach = function(layer) { 'use strict'; return new FastClick(layer);};
在FastClick的构造函数中
this.onClick = function() { return FastClick.prototype.onClick.apply(self, arguments); }; this.onMouse = function() { return FastClick.prototype.onMouse.apply(self, arguments); }; this.onTouchStart = function() { return FastClick.prototype.onTouchStart.apply(self, arguments); }; this.onTouchEnd = function() { return FastClick.prototype.onTouchEnd.apply(self, arguments); }; this.onTouchCancel = function() { return FastClick.prototype.onTouchCancel.apply(self, arguments); }; if (FastClick.notNeeded(layer)) { return; } if (this.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('touchend', this.onTouchEnd, false); layer.addEventListener('touchcancel', this.onTouchCancel, false);
也就是在document.body上绑定了click,touchstart,touchend,touchcancel事件。这里假设,我们的页面有一个button,绑定了click事件。当用户点击此button时,会先触发touchstart事件,这时,会冒泡到document.body中,于是就会执行:
FastClick.prototype.onTouchStart = function(event) { 'use strict'; var targetElement, touch, selection; if (event.targetTouches.length > 1) { return true; } targetElement = this.getTargetElementFromEventTarget(event.target); touch = event.targetTouches[0]; if (this.deviceIsIOS) { selection = window.getSelection(); if (selection.rangeCount && !selection.isCollapsed) { return true; } if (!this.deviceIsIOS4) { if (touch.identifier === this.lastTouchIdentifier) { event.preventDefault(); return false; } this.lastTouchIdentifier = touch.identifier; this.updateScrollParent(targetElement); } } this.trackingClick = true; this.trackingClickStart = event.timeStamp; this.targetElement = targetElement; this.touchStartX = touch.pageX; this.touchStartY = touch.pageY; if ((event.timeStamp - this.lastClickTime) < 200) { event.preventDefault(); } return true;};
这个回调函数主要做了以下事情:
- 获取我们当前触发touchstart的元素,这里是button。
- 然后将鼠标的信息记录了下来,记录鼠标的信息主要是为了在后面touchend触发时,根据这里得到的x、y判断是否为click。
- 触发touchend事件,然后冒泡到document.body上,执行以下代码:
FastClick.prototype.onTouchEnd = function(event) { 'use strict'; var forElement, trackingClickStart, targetTagName, scrollParent, touch, targetElement = this.targetElement; if (this.touchHasMoved(event) || (event.timeStamp - this.trackingClickStart) > 300) { this.trackingClick = false; this.targetElement = null; } if (!this.trackingClick) { return true; } if ((event.timeStamp - this.lastClickTime) < 200) { this.cancelNextClick = true; return true; } this.lastClickTime = event.timeStamp; trackingClickStart = this.trackingClickStart; this.trackingClick = false; this.trackingClickStart = 0; if (this.deviceIsIOSWithBadTarget) { touch = event.changedTouches[0]; targetElement = document.elementFromPoint(touch.pageX - window.pageXOffset, touch.pageY - window.pageYOffset); } targetTagName = targetElement.tagName.toLowerCase(); if (targetTagName === ‘label‘) { forElement = this.findControl(targetElement); if (forElement) { this.focus(targetElement); if (this.deviceIsAndroid) { return false; } targetElement = forElement; } } else if (this.needsFocus(targetElement)) { if ((event.timeStamp - trackingClickStart) > 100 || (this.deviceIsIOS && window.top !== window && targetTagName === ‘input‘)) { this.targetElement = null; return false; } this.focus(targetElement); if (!this.deviceIsIOS4 || targetTagName !== 'select') { this.targetElement = null; event.preventDefault(); } return false; } if (this.deviceIsIOS && !this.deviceIsIOS4) { scrollParent = targetElement.fastClickScrollParent; if (scrollParent && scrollParent.fastClickLastScrollTop !== scrollParent.scrollTop) { return true; } } if (!this.needsClick(targetElement)) { event.preventDefault(); this.sendClick(targetElement, event); } return false;};
注意上面的代码中,event.preventDefault();会阻止真实的click事件的触发,因此,在button上面的click事件不会触发。接下来,我们只需要查看sendClick方法。
FastClick.prototype.sendClick = function(targetElement, event) { 'use strict'; var clickEvent, touch; if (document.activeElement && document.activeElement !== targetElement) { document.activeElement.blur(); } touch = event.changedTouches[0]; clickEvent = document.createEvent(‘MouseEvents‘); clickEvent.initMouseEvent(‘click‘, true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null); clickEvent.forwardedTouchEvent = true; targetElement.dispatchEvent(clickEvent);};
在此方法中,会创建一个自定义的click事件,然后在button上立即触发,于是,button绑定的click的事件回调函数马上执行,因此就没有300ms延迟了。
上面的initMouseEvent方法的前三个参数的意思:1.事件类型,2.是否冒泡,3.是否阻止浏览器的默认行为。
自定义的click事件阻止了浏览器的默认行为,事件冒泡,于是执行document.body的click事件回调函数。代码如下:
FastClick.prototype.onClick = function(event) { 'use strict'; var permitted; if (this.trackingClick) { this.targetElement = null; this.trackingClick = false; return true; } if (event.target.type === ‘submit‘ && event.detail === 0) { return true; } permitted = this.onMouse(event); if (!permitted) { this.targetElement = null; } return permitted;};
然后里面有一句 permitted = this.onMouse(event);于是,我们查看onMouse方法:
FastClick.prototype.onMouse = function(event) { 'use strict'; if (!this.targetElement) { return true; } if (event.forwardedTouchEvent) { return true; } if (!event.cancelable) { return true; } if (!this.needsClick(this.targetElement) || this.cancelNextClick) { if (event.stopImmediatePropagation) { event.stopImmediatePropagation(); } else { event.propagationStopped = true; } event.stopPropagation(); event.preventDefault(); return false; } return true;};
这个方法会阻止模拟的click事件的冒泡以及默认行为,于是就解决了移动端浏览器click事件延迟300ms的问题。代码比较长,大家能看懂7788就差不多了 ^_^
不足
唯一的缺点可能也就是该脚本的文件尺寸 (尽管它只有 10kb)。如果你非常在意这点文件大小,可以尝试一下 Filament Group 的 Tappy!,或者 tap.js。两者都相当轻量,能够通过监听tap而非click事件来绕过 300 毫秒延迟。
@参考 移动端click事件延迟300ms的原因以及解决办法
- 深入解析FastClick解决延迟点击
- JavaScript ---- fastclick解决IOS点击300毫秒延迟
- 点击穿透与FastClick浅读
- fastclick.js解决移动端(ipad)点击事件反应慢问题
- vue移动端项目解决 延迟点击
- 解决IOS点击延迟跳转的问题
- fastclick
- 解决tableview上按钮点击效果的延迟现象
- 解决ios下,点击延迟300ms的办法
- 深入解析Mysql 主从同步延迟原理及解决方案
- 深入分析Linux sync命令,解决延迟写入问题
- FastClick消除点击延时提高程序的运行效率
- FastClick消除点击延时提高程序的运行效率
- 有关RADIOBUTTON点击延迟
- 5步解决移动设备上的300ms点击延迟
- 微信开发:解决IOS端下面的点击延迟问题
- 5步解决移动设备上的300ms点击延迟
- perfect-scrollbar 和 fastclick 整合后首次需要点击两次的处理
- Java大数运算
- 核心动画-雪花
- SWT中的多线程
- Windows/DOS与Unix文件格式之间的相互转换(/r/n问题)
- Python面相对象
- 深入解析FastClick解决延迟点击
- 优先队列的初始化,删除,插入操作
- new和malloc的区别
- pushd popd shift ATTRIB
- CALayer的使用
- 用python开启简单服务器
- DS18B20
- 通俗地理解Swift语言计算属性
- sicily 1205. brainf*ck