移动手机端click事件件延迟300ms到底是怎么回事,该如何解决

移动端click事件延迟300ms到底是怎么回事,该如何解决?!
由于两次连续“轻触”是“放大”的操作(即使你两次轻触的是一个链接或一个有click事件监听器的元素),
所以在第一次被“轻触”后,浏览器需要先等一段时间,看看有没有所谓的“连续的第二次轻触”
。如果有,则进行“放大”操作。没有,才敢放心地认为用户不是要放大,而是需要“click”至此才敢触发click事件,
导致“短按(手指接触屏幕到离开屏幕的时间比较短)”的click事件通常约会延迟300ms左右。
采用touchstart代替click是比较初级的解决方案,首先,touchstart和click的触发条件就有区别,对于手持设备的浏览器:
1.touchstart:在这个dom(或冒泡到这个dom,这当然是废话)上手指触摸开始即能触发
2.click:在这个dom(或冒泡到这个dom,这当然是废话)上手指触摸开始,且手指未曾在屏幕上移动(某些浏览器允许移动一个非常小的位移值),且在这个在这个dom上手指离开屏幕,且触摸和离开屏幕之间的间隔时间较短(某些浏览器不检测间隔时间,也会触发click)才能触发
于是我们可以看到,完全用touchstart代替是不太可取的。
根据上面的区别,又要规避click在移动手持设备上带来的延迟,很容易有了模拟的办法,大致思路是:
在touchstart、touchend时记录时间、手指位置,在touchend时进行比较,如果手指位置为同一位置(或允许移动一个非常小的位移值)且时间间隔较短(一般认为是200ms),且过程中未曾触发过touchmove,即可认为触发了手持设备上的“click”,一般称它为“tap”
zepto已经封装了上述tap
3.FastClick
:一个简单,易于使用的JS库用于消除在移动浏览器上触发click事件与一个物理Tap(敲击)之间的300延迟。
它支持以下浏览器:
Mobile Safari on&&3
and upwards
Chrome on iOS 5 and upwards
Chrome on&&(ICS)
Opera Mobile 11.5 and upwards
Android Browser since Honeycomb
PlayBook OS 1 and upwards
对于非移动浏览器不启作用,禁用缩放标。
FastClick.attach(document.body);
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。移动端click事件延迟300ms的原因以及解决办法 - chaojidan - 博客园
这要追溯至 2007 年初。苹果公司在发布首款 iPhone 前夕,遇到一个问题 && 当时的网站都是为大屏幕设备所设计的。于是苹果的工程师们做了一些约定,应对 iPhone 这种小屏幕浏览桌面端站点的问题。这当中最出名的,当属双击缩放(double tap to zoom)。这也是会有上述 300 毫秒延迟的主要原因。
当用户一次点击屏幕之后,浏览器并不能立刻判断用户是要进行双击缩放,还是想要进行单击操作。因此,iOS Safari 就等待 300 毫秒,以判断用户是否再次点击了屏幕。
于是,300 毫秒延迟就这么诞生了。
&是&&专门为解决移动端浏览器 300 毫秒点击延迟问题所开发的一个轻量级的库。简而言之,FastClick 在检测到&touchend&事件的时候,会通过&立即触发一个模拟click&事件的click事件(自定义事件),并把浏览器在 300 毫秒之后真正触发的&click&事件阻止掉。
FastClick 非常实际地解决 300 毫秒点击延迟的问题。唯一的缺点可能也就是该脚本的文件尺寸 (尽管它不大)。如果你非常在意这点文件大小,可以尝试一下&&的&,或者&。两者都相当轻量,能够通过监听&tap&而非&click&事件来绕过 300 毫秒延迟。
当然,zepto库函数中,也有一个touch模块,此模块也包含tap事件,可以通过绑定tap来取代click事件。
但是zepto的tap事件会有点透问题。如何解决,请看下篇分解。
接下来,我们来详细了解一个问题:FastClick解决延迟点击的源码解析。
FastClick解决延迟点击的源码解析。
首先,我们来看FastClick的使用。
window.addEventListener( "load", function() {
FastClick.attach( document.body );
}, false );
这样就解决了 300 毫秒点击延迟的问题。
FastClick的源码:
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)) {
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,
if (event.targetTouches.length & 1) {
targetElement = this.getTargetElementFromEventTarget(event.target);
touch = event.targetTouches[0];
if (this.deviceIsIOS) {
selection = window.getSelection();
if (selection.rangeCount && !selection.isCollapsed) {
if (!this.deviceIsIOS4) {
if (touch.identifier === this.lastTouchIdentifier) {
event.preventDefault();
this.lastTouchIdentifier = touch.
this.updateScrollParent(targetElement);
this.trackingClick =
this.trackingClickStart = event.timeS
this.targetElement = targetE
this.touchStartX = touch.pageX;
this.touchStartY = touch.pageY;
if ((event.timeStamp - this.lastClickTime) & 200) {
event.preventDefault();
这个回调函数主要做了以下事情:
获取我们当前触发touchstart的元素,这里是button。
然后将鼠标的信息记录了下来,记录鼠标的信息主要是为了在后面touchend触发时,根据这里得到的x、y判断是否为click。
之后,会触发touchend事件,然后冒泡到document.body上,执行以下代码:
FastClick.prototype.onTouchEnd = function(event) {
'use strict';
var forElement, trackingClickStart, targetTagName, scrollParent, touch, targetElement = this.targetE
if (this.touchHasMoved(event) || (event.timeStamp - this.trackingClickStart) & 300) {
this.trackingClick =
this.targetElement =
if (!this.trackingClick) {
if ((event.timeStamp - this.lastClickTime) & 200) {
this.cancelNextClick =
this.lastClickTime = event.timeS
trackingClickStart = this.trackingClickS
this.trackingClick =
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) {
targetElement = forE
} else if (this.needsFocus(targetElement)) {
if ((event.timeStamp - trackingClickStart) & 100 || (this.deviceIsIOS && window.top !== window && targetTagName === 'input')) {
this.targetElement =
this.focus(targetElement);
if (!this.deviceIsIOS4 || targetTagName !== 'select') {
this.targetElement =
event.preventDefault();
if (this.deviceIsIOS && !this.deviceIsIOS4) {
scrollParent = targetElement.fastClickScrollP
if (scrollParent && scrollParent.fastClickLastScrollTop !== scrollParent.scrollTop) {
if (!this.needsClick(targetElement)) {
event.preventDefault();
this.sendClick(targetElement, event);
注意上面的代码中,event.preventDefault();会阻止真实的click事件的触发,因此,在button上面的click事件不会触发。
接下来,我们只需要查看sendClick方法。
FastClick.prototype.sendClick = function(targetElement, event) {
'use strict';
var clickEvent,
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 =
targetElement.dispatchEvent(clickEvent);
在此方法中,会创建一个自定义的click事件,然后在button上立即触发,于是,button绑定的click的事件回调函数马上执行,因此就没有300ms延迟了。
上面的initMouseEvent方法的前三个参数的意思:1.事件类型,2.是否冒泡,3.是否阻止浏览器的默认行为。
自定义的click事件阻止了浏览器的默认行为,事件冒泡,于是执行document.body的click事件回调函数。代码如下:
FastClick.prototype.onClick = function(event) {
'use strict';
if (this.trackingClick) {
this.targetElement =
this.trackingClick =
if (event.target.type === 'submit' && event.detail === 0) {
permitted = this.onMouse(event);
if (!permitted) {
this.targetElement =
然后里面有一句 permitted = this.onMouse(event);于是,我们查看onMouse方法:
FastClick.prototype.onMouse = function(event) {
'use strict';
if (!this.targetElement) {
if (event.forwardedTouchEvent) {
if (!event.cancelable) {
if (!this.needsClick(this.targetElement) || this.cancelNextClick) {
if (event.stopImmediatePropagation) {
event.stopImmediatePropagation();
event.propagationStopped =
event.stopPropagation();
event.preventDefault();
此方法,会阻止模拟的click事件的冒泡以及默认行为。
到此,解决了移动端浏览器click事件延迟300ms的问题。
加油!  移动端浏览器采用click时间会有300ms延迟,为什么_百度知道
移动端浏览器采用click时间会有300ms延迟,为什么
我有更好的答案
解决方法fastclick可以解决在手机上点击事件的300ms延迟zepto的touch模块,tap事件也是为了解决在click的延迟问题解决300ms延迟的问题,也可以通过绑定ontouchstart事件,加快对事件的响应
采纳率:94%
来自团队:
为您推荐:
其他类似问题
浏览器的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。495被浏览26,243分享邀请回答208 条评论分享收藏感谢收起2添加评论分享收藏感谢收起

我要回帖

更多关于 移动端 click事件 的文章

 

随机推荐