一.click与300ms延迟

移动浏览器提供一个特殊的功能:双击(double tap)放大

300ms的延迟就来自这里,用户碰触页面之后,需要等待一段时间来判断是不是双击(double tap)动作,而不是立即响应单击(click),等待的这段时间大约是300ms。之前有过简单介绍: 黯羽轻扬:HTML5触摸事件

移动事件提供了 touchstart 、 touchmove 、 touchend 却没有提供tap支持,主流框架(库)都是手动实现了自定义tap事件,以求消除300ms延迟,提高页面响应速度。对于简单的页面,可以把 touchstart 或者 touchend 当作tap来用,但存在一些问题,比如手指接触目标元素,按住不放,慢慢移出响应区域,会触发 touchstart 事件执行对应的事件处理器(本不应该触发), touchend 事件也存在类似的问题。

此外, 使用原生touch事件也存在点击穿透的问题 ,因为click是在touch系列事件发生后大约300ms才触发的,混用touch和click肯定会导致点透问题,下面详细介绍

二.点击穿透问题

点击穿透现象有3种:

  • 点击穿透问题:点击蒙层(mask)上的关闭按钮,蒙层消失后发现触发了按钮下面元素的click事件

    蒙层的关闭按钮绑定的是touch事件,而按钮下面元素绑定的是click事件,touch事件触发之后,蒙层消失了,300ms后这个点的click事件fire,event的target自然就是按钮下面的元素,因为按钮跟蒙层一起消失了

  • 跨页面点击穿透问题:如果按钮下面恰好是一个有href属性的a标签,那么页面就会发生跳转

    因为 a标签跳转默认是click事件触发 ,所以原理和上面的完全相同

  • 另一种跨页面点击穿透问题:这次没有mask了,直接点击页内按钮跳转至新页,然后发现新页面中对应位置元素的click事件被触发了

    和蒙层的道理一样,js控制页面跳转的逻辑如果是绑定在touch事件上的,而且新页面中对应位置的元素绑定的是click事件,而且页面在300ms内完成了跳转,三个条件同时满足,就出现这种情况了

非要细分的话还有第四种,不过概率很低,就是新页面中对应位置元素恰好是a标签,然后就发生连续跳转了。。。诸如此类的,都是点击穿透问题

三.解决方案

问题已经很明了了,有很多解决方案,但思路不外乎2种:

  1. 不要混用touch和click

    既然touch之后300ms会触发click,只用touch或者只用click就自然不会存在问题了

  2. 吃掉(或者说是消费掉)touch之后的click

    依旧用tap,只是在可能发生点击穿透的情形做额外的处理,拿个东西来挡住、或者tap后延迟350毫秒再隐藏mask、pointer-events、在下面元素的事件处理器里做检测(配合全局flag)等等,能吃掉就行

详细解决方案:

  1. 只用touch

    最简单的解决方案,完美解决点击穿透问题

    把页面内所有click全部换成touch事件( touchstart 、’touchend’、’tap’),需要特别注意 a标签,a标签的href也是click,需要去掉换成js控制的跳转,或者直接改成span + tap控制跳转。如果要求不高,不在乎滑走或者滑进来触发事件的话,span + touchend就可以了,毕竟tap需要引入第三方库

    不用a标签其实没什么,移动app开发不用考虑SEO,即便用了a标签,一般也会去掉所有默认样式,不如直接用span

  2. 只用click

    下下策 ,因为会带来300ms延迟,页面内任何一个自定义交互都将增加300毫秒延迟,想想都慢

    不用touch就不会存在touch之后300ms触发click的问题,如果交互性要求不高可以这么做, 强烈不推荐 ,快一点总是好的

  3. 拿个东西来挡住

    比较笨的方法, 千万不要用

    叶小钗的“菊花”大法,更多信息请查看 【移动端兼容问题研究】javascript事件机制详解(涉及移动兼容)

  4. tap后延迟350ms再隐藏mask

    改动最小,缺点是隐藏mask变慢了,350ms还是能感觉到慢的

    只需要针对mask做处理就行,改动非常小,如果要求不高的话,用这个比较省力

  5. pointer-events

    比较麻烦且有缺陷, 不建议使用

    mask隐藏后,给按钮下面元素添上 pointer-events: none; 样式,让click穿过去,350ms后去掉这个样式,恢复响应

    缺陷是mask消失后的的350ms内,用户可以看到按钮下面的元素点着没反应,如果用户手速很快的话一定会发现

  6. 在下面元素的事件处理器里做检测(配合全局flag)

    比较麻烦, 不建议使用

    全局flag记录按钮点击的位置(坐标点),在下面元素的事件处理器里判断event的坐标点,如果相同则是那个可恶的click,拒绝响应

    上面说的只是想法,没测试过,实在不行就用记录时间戳判断,等待350ms,这样就和 pointer-events 差不多

  7. fastclick

    好用的解决方案,不介意多加载几KB的话, 不建议使用 ,因为有人遇到了bug,更多信息请查看: Fastclick 导致click事件触发两次的问题

    首先引入fastclick库,再把页面内所有touch事件都换成click,其实稍微有点麻烦,建议引入这几KB就为了解决点透问题不值得,不如用第一种方法呢

四.DEMO

写了不少测试页面,请查看: Git@OSC ayqy / my.js

参考资料

  • 前辈博文若干

点击穿透问题(http://www.tuicool.com/articles/6NfaUnM)的更多相关文章

  1. hitTest:withEvent:方法(此方法可实现点击穿透、点击下层视图功能)

    此方法可实现点击穿透.点击下层视图功能 一. hitTest:withEvent:调用过程 iOS系统检测到手指触摸(Touch)操作时会将其放入当前活动Application的事件队列,UIAppl ...

  2. pointer-events属性屏蔽鼠标事件(点击穿透上层元素)

    应用场景 我们在 HTML 开发时可能会遇到这样的情况:页面上有一些元素使用绝对定位布局,这些元素可能会遮盖住它们位置下方的某个元素的部分或者全部.默认情况下,下方元素被遮挡的部分是不会响应鼠标事件的 ...

  3. 微信小程序弹出层点击穿透问题

    问题描述:使用小程序的modal组件实现遮罩层效果时,会出现滚动穿透的问题,即遮罩层后面的页面依旧可以滚动. 解决方案: 给底层页面动态添加 position:fixed; 代码: wxml: < ...

  4. IE8 没有内容的盒子,如果有定位,浮现在其他盒子上 可能会有点击穿透没有作用的情况

    IE8 没有内容的盒子,如果有定位,浮现在其他盒子上 可能会有点击穿透没有作用的情况

  5. 说说移动端web开发中的点击穿透问题

    最近一直在忙于一个无线端的项目,由于之前主要工作都是在桌面端,移动端接触的比较少,所以中间遇到了很多的坑,做一个简单的记录. 问题背景 需求中有这样的一个功能,点击取件信息的时候会弹出一个地址列表的浮 ...

  6. document.onclick在ios上不触发的解决方法与touchstart点击穿透处理

    document.onclick = function (e) { var e = e ? e : window.event; var tar = e.srcElement || e.target; ...

  7. UGUI 点击穿透问题

    unity上 用 做游戏欢迎界面上通用的ui,然后导到游戏里面直接用,但发现游戏里面是用ngui的,点击ugui 的ui 会穿透过去 ngui会响应,原本模型的点击处理也会响应 我用的 unity 版 ...

  8. jquery鼠标点击穿透的解决方法

    jquery鼠标点击穿透的解决方法 <pre><div class="showcontainer" style="background:#000;dis ...

  9. Android Fragment 多层叠加时点击穿透解决方案

    一.问题现象 多层fragment叠加时,点击上层fragment会使下层fragment的控件对应点击事件响应,这种现象就是点击穿透. 对于这种情况,我们一般都是对baseFragment进行vie ...

随机推荐

  1. SpringMVC(三)

    今天是学习Spring的第四天,今天终于又把Spring+SpringMVC+Mybatis(SSM)高了一遍,这次运行的代码和配置和昨天的不一样,今天运行的很成功. 主要学习的一点就是我今天使用的是 ...

  2. (一)Bootstrap简介

    Bootstrap 是一个用于快速开发 Web 应用程序和网站的前端框架.Bootstrap 是基于 HTML.CSS.JAVASCRIPT 的. Bootstrap优点: 移动设备优先:自 Boot ...

  3. .Net基础学习

    http://www.cnblogs.com/iPragmatic/p/4930396.html memcache的介绍与应用场景 http://www.cnblogs.com/nixi8/p/493 ...

  4. eclipse代码左虚线对齐设置

    前言 : 前阵子看到同事的eclipse左边有虚线对齐.有点好奇~刚开始以为是装了神马插件, 于是百度了下, 貌似没有找着. 一怒之下,逗比了半个小时,终于探索出来了~~ 设置如下 : 点击confi ...

  5. JNI-数据类型

    转载:http://blog.csdn.net/conowen/article/details/7523145 在Java中有两类数据类型:primitive types,如,int, float, ...

  6. 提高你的Java代码质量吧:少用静态导入

    一.分析  从Java 5开始引入静态导入语法(import static),其目的是为了减少字符输入量,提高代码的可阅读性,以便更好地理解程序. 但是,滥用静态导入会使程序更难阅读,更难维护.静态导 ...

  7. Zookeeper全解析——Paxos作为灵魂

    原文地址: http://www.spnguru.com/2010/08/zookeeper%E5%85%A8%E8%A7%A3%E6%9E%90%E2%80%94%E2%80%94paxos%E7% ...

  8. 教你50招提升ASP.NET性能(四):精选的技巧

    (4)A selection of tips 招数4: 精选的技巧 Make sure HTTP compression is turned on for any uncompressed conte ...

  9. poj 1904 King's Quest tarjan求二分图的所有可选最大匹配边

    因为是完美匹配,所以每个点都已经匹配了,那么如果要选择一条别的边,增光路的最后必定找到原来所匹配的点,加上匹配的边,那么就是一个环.所以可选边在一个强连通分量里. #include <iostr ...

  10. java nio 抛出NonWritableChannelException异常

    抛出异常的代码在此处: MappedByteBuffer buffer = channel.map(MapMode.READ_WRITE, 0, avalible); 其中channel是一个file ...