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

&meta name="viewport" content="width=device-width, user-scalable=no"&
&meta name="viewport" content="width=device-width, user-scalable=no"&
&meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1"&
&meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1"&
但是这一方案在 safari 上并不起作用,还会降低有视觉或运动障碍用户的可访问性。
3、设置 viewport 的 device-width (chrome 32+)
在 chrome 32+ 中,如果设置了 viewport 的宽度小于或等于物理设备的宽度,那么也会达到禁用缩放的效果。
&meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=3"&
&meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=3"&
注意:这里的最大缩放比与上面meta中的值并不一致,这个是关键点。
4、使用指针事件 (IE10+)
微软已经针对触摸问题发布了具体的规范,例如:在你滚屏的时候 pointerup 事件并不会被触发。
这儿有一个非标准的 CSS 触摸 action 属性,它允许你移除特定元素或整个文档的触发延迟,而无需禁用缩放:
a, button, .myelements {
-ms-touch-action: /* IE10
touch-action:
/* IE11+ */
a, button, .myelements {&&&&-ms-touch-action: manipulation; /* IE10&&*/&&&&touch-action: manipulation;&&&& /* IE11+ */}
5、使用 touchend 事件处理
不同于 click 和 touchstart,touchend 没有这个 300ms 的延迟,而是即时触发,你完全可以在 WebGL 或 canvase 游戏中进行实践,但是在web 页面中单单使用 touchend 并不一定靠谱.
1、如果用户在两个不同元素之间触发了 touchstart 和touchend,那么 click 不会被触发 .
2、如果用户触发了 touchstart,但是在touchend之前是一个长长的 touchmove 滚动, 那么 click 也不会被触发.
3、在站点上任然应该保留 click 事件以兼容那些非触摸设备,这是你就要考虑事件的重复触发问题.
在此处输入内容已有同行为我们封装了部分解决方法:
1、&来至于FT实验室的一个插件,仅仅只有10kb,但是能解决上面的2-4步.
2、&来自于Filament Group,仅仅1kb,概念上类似于上面的指针事件.
问题:当你为多个元素进行这些事件绑定时,有可能出现性能的损耗.
是否有完美的解决方案呢?
是否需要解决 300ms 在于自己的判断,300ms被设计出来是有特定的用途,上面的meta属性中进行了设定,在chrome和firefox下能起作用,希望其他厂商也能尽快提供这类支持。touch-action: manipulation 这个css属性能把风险降到最低,虽然现在只有微软支持,但是作为W3C规范和HTML5test的一部分,因此也许我们并不需要等待太久。
转自:/?p=524
本文固定链接:
【上一篇】【下一篇】
您可能还会对这些文章感兴趣!
最新日志热评日志随机日志
日志总数:94 篇
评论总数:76 篇
标签数量:27 个
链接总数:15 个
建站日期:
运行天数:2029 天
最后更新:> 博客详情
为了防止误操作,移动端iOS操作系统针对原生click事件做了300ms的延迟,这在一定程度上影响了我们的使用体验。
现在有现成的插件fastclick可以解决这个问题,但是也有弊端:
GitHub上最新版本的插件大小为25.4kb,轻量为趋势,能省则省。
它的核心思想是取消默认的click时间,判断当前dom节点的类型进行相应的操作,这个判断过程较为繁琐。
MyTapEvent
本人最近在做微信项目,由于fastclick插件存在一定弊端,因此开发了一个简单的tap事件,主要思想有以下几点:
一次tap事件包含touchstart和touchmove(轻微移动)以及touchend三种状态
callback方法在touchend后执行
根据chrome浏览器默认的判断取消点击的移动量,手指偏移量(水平或垂直)超过15px则判定为滚动,取消执行tap事件
手指按下时间过长不视为点击,默认时间间隔为500ms
使用HTMLElement来扩充原型,方便添加Event
使用单例模式,确保只加载一次
ok,思想定下来,代码写起来就清晰多了:
if (!HTMLElement.prototype.addTapEvent) {
HTMLElement.prototype.addTapEvent = function(callback) {
var tapStartTime = 0,
tapEndTime = 0,
tapTime = 500, //tap等待时间,在此事件下松开可触发方法
tapStartClientX = 0,
tapStartClientY = 0,
tapEndClientX = 0,
tapEndClientY = 0,
tapScollHeight = 15, //水平或垂直方向移动超过15px测判定为取消(根据chrome浏览器默认的判断取消点击的移动量)
cancleClick =
this.addEventListener('touchstart', function() {
tapStartTime = event.timeS
var touch = event.changedTouches[0];
tapStartClientX = touch.clientX;
tapStartClientY = touch.clientY;
cancleClick =
this.addEventListener('touchmove', function() {
var touch = event.changedTouches[0];
tapEndClientX = touch.clientX;
tapEndClientY = touch.clientY;
if ((Math.abs(tapEndClientX - tapStartClientX) & tapScollHeight) || (Math.abs(tapEndClientY - tapStartClientY) & tapScollHeight)) {
cancleClick =
this.addEventListener('touchend', function() {
tapEndTime = event.timeS
if (!cancleClick && (tapEndTime - tapStartTime) &= tapTime) {
callback();
HTMLElement.addTapEvent(function(){
//do something...
document.querySelect('#test').addTapEvent(function(){
alert('this is a tap event');
这里给一个移动端案例,同时也包含了闭包的知识,前20项为tap事件,后30项为click事件,大家可以在手机上试一下效果,感受一下两种方法的差别:
&style media="screen"&
padding: 20
&!DOCTYPE html&
&meta charset="utf-8"&
&meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"&
&meta name="apple-mobile-web-app-capable" content="yes"&
&meta name="apple-touch-fullscreen" content="yes"&
&meta name="apple-mobile-web-app-status-bar-style" content="black"&
&meta name="format-detection" content="telephone=no,email=no"&
&meta name="x5-orientation" content="portrait"&
&title&test&/title&
&script type="text/javascript"&
if (!HTMLElement.prototype.addTapEvent) {
HTMLElement.prototype.addTapEvent = function(callback) {
var tapStartTime = 0,
tapEndTime = 0,
tapTime = 500, //tap等待时间,在此事件下松开可触发方法
tapStartClientX = 0,
tapStartClientY = 0,
tapEndClientX = 0,
tapEndClientY = 0,
tapScollHeight = 15, //水平或垂直方向移动超过15px测判定为取消(根据chrome浏览器默认的判断取消点击的移动量)
cancleClick =
this.addEventListener('touchstart', function() {
tapStartTime = event.timeS
var touch = event.changedTouches[0];
tapStartClientX = touch.clientX;
tapStartClientY = touch.clientY;
cancleClick =
this.addEventListener('touchmove', function() {
var touch = event.changedTouches[0];
tapEndClientX = touch.clientX;
tapEndClientY = touch.clientY;
if ((Math.abs(tapEndClientX - tapStartClientX) & tapScollHeight) || (Math.abs(tapEndClientY - tapStartClientY) & tapScollHeight)) {
cancleClick =
this.addEventListener('touchend', function() {
tapEndTime = event.timeS
if (!cancleClick && (tapEndTime - tapStartTime) &= tapTime) {
callback();
var ul = document.querySelector('ul');
for (var i = 1; i &= 20; i++) {
var li = document.createElement('li');
li.innerHTML =
li.addTapEvent(function() {
return function() {
ul.appendChild(li);
for (var j = 21; j &= 50; j++) {
var li = document.createElement('li');
li.innerHTML =
li.onclick = function() {
return function() {
ul.appendChild(li);
人打赏支持
码字总数 22677
哈哈,这个方法一般都是自己用,基本功能可以实现。不过我很同意你的说法,有空我试一下
你可以先试一下。。。我那个demo是有click和tap的对比的
引用来自“Simon_ITer”的评论你可以先试一下。。。我那个demo是有click和tap的对比的我在我的小米4(Android 6)上测试过WebView和小米浏览器,加了我上面提到的那句viewport后,300ms延迟就没有了,300ms的延迟人是能感受得到的,我测试的是文件上传按钮.
引用来自“Simon_ITer”的评论你可以先试一下。。。我那个demo是有click和tap的对比的引用来自“eechen”的评论我在我的小米4(Android 6)上测试过WebView和小米浏览器,加了我上面提到的那句viewport后,300ms延迟就没有了,300ms的延迟人是能感受得到的,我测试的是文件上传按钮.我那个Demo只是方便移动端测试的,click的延迟确实还存在。不过话说回来,我这篇文章重点在tap的解决方案,demo只是方便测试放上去的
支付宝支付
微信扫码支付
打赏金额: ¥
已支付成功
打赏金额: ¥
& 开源中国(OSChina.NET) |
开源中国社区(OSChina.net)是工信部
指定的官方社区fastclick与zepto的 tap事件关于在手机上click事件的300ms延迟的区别 - hlily - 推酷
fastclick与zepto的 tap事件关于在手机上click事件的300ms延迟的区别 - hlily
之前翻译过一篇关于fastclick的快速点击文章
,fastclick可以解决在手机上点击事件的300ms延迟;另外我们也知道zepto的touch模块,帮助我们实现了很多手机上的事件,比如tap等,tap事件也是为了解决在click的延迟问题。那么他们有什么区别呢?
先看zepto的touch模块实现:
1 $(document)
.on('touchstart ...',function(e){
now = Date.now()
delta = now - (touch.last || now)
if (delta & 0 && delta &= 250) touch.isDoubleTap = true
touch.last = now
.on('touchmove ...', function(e){
.on('touchend ...', function(e){
if (deltaX & 30 && deltaY & 30) {
var event = $.Event('tap')
touch.el.trigger(event)
touch模块绑定事件touchstart,touchmove和touchend到document上,然后通过计算touch事件触发的时间差,位置差来实现了自定义的tap,swipe等。
那么tap事件为什么会“穿透”呢?
比如下面的代码:
&meta charset=&UTF-8&&
&script type=&text/javascript& src=&/resources/js/zepto.js&&&/script&
&script type=&text/javascript& src=&/resources/js/zepto-touch.js&&&/script&
&title&&/title&
.q{width: 200height: 200background-color:position:top:0;;left: 0}
.b{width: 300height: 300background-color:position:top:0;;left: 0}
&div class=&b&&&/div&
&div class=&q&&&/div&
$('.q').on('tap',function(e){
$(this).hide();
$('.b').on('click',function(e){
alert(&bb&);
在手机上,点击了q以后,就会弹出bb的弹框,为什么呢?
因为tap事件是通过document绑定了touchstart和touchend事件实现,$('.q')上,当touchend事件冒泡到document上以后执行$(this).hide();此时$('.b'),就处在了页面的最前面,
现在touchend冒泡到了document上,并且$('.b')在页面的最前面,然后就触发了click事件。
关于click事件300ms延迟的由来,以及随着时间的发展,遇到的问题,各家浏览器的解决方法和现在的各种js的方法,可以见
&准备翻译下。因为里面也介绍了fastclick,呵呵。
所以zepto的touch模块真的不是一个好的模块。。不过比我自己写的好,关键是为什么一直都不解决这个点透的问题啊。。
fastclick呢?
它的实际原理是在
上绑定touchstart ,touchend事件,然后在touchend结束的时候立马执行click事件,这样就解决了“点透”的问题(实质是事件冒泡导致)以及300ms延迟问题,300ms延迟是因为浏览器为了实现用户双击屏幕放大页面(double tap to zoom 详细见我下一篇翻译吧)的效果。
FastClick.prototype.sendClick = function(targetElement, event) {
'use strict';
var clickEvent,
// 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事件
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.dispatchEvent(clickEvent);
在touchEnd的时候会立马调用这个sendClick
FastClick.prototype.onTouchEnd = function(event){
this.sendClick(targetElement, event);
好了,这两个就是这样了。
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致&&国之画&&&& &&&&&&
&& &&&&&&&&&&&&&&
鲁ICP备号-4
打开技术之扣,分享程序人生!

我要回帖

更多关于 click事件 300ms延迟 的文章

 

随机推荐