zepto学习(二)之tap事件以及tap事件点透处理
前言
为什么通过touch可以触发click事件?
touch事件的来源
PC网页上的大部分操作都是用鼠标的,即响应的是鼠标事件,包括mousedown
、mouseup
、mousemove
和click
事件。一次点击行为,事件的触发过程为:mousedown
-> mouseup
-> click
三步。
手机上没有鼠标,所以就用触摸事件去实现类似的功能。touch事件包含touchstart
、touchmove
、touchend
,注意手机上并没有tap
事件。手指触发触摸事件的过程为:touchstart
-> touchmove
-> touchend
。
手机上没有鼠标,但不代表手机不能响应mouse事件(其实是借助touch去触发mouse事件)。有人在PC和手机上对事件做了对比实验,以说明手机对touch事件响应速度快于mouse事件。
可以看到在手机上,当我们手触碰屏幕时,要过300ms左右才会触发mousedown
事件,所以click
事件在手机上看起来就像慢半拍一样。
tap是怎么来的
我们在上面看到,手机上响应 click 事件会有300ms的延迟,那么这300ms到底是干嘛了?浏览器在 touchend 后会等待约300ms,原因是判断用户是否有双击(double tap)行为(主要原因是苹果手机在设计时,考虑到用户在浏览网页时需要放大)。如果没有 tap 行为,则触发 click 事件,而双击过程中就不适合触发 click 事件了。由此可以看出 click 事件触发代表一轮触摸事件的结束。
既然说tap事件是模拟出来的,我们可以看下Zepto对 singleTap 事件的处理。见源码 136-143 行,可以看出在 touchend 响应 250ms 无操作后,则触发singleTap。
注意:singleTap和doubleTap分别代表单次点击和双次点击。
点击穿透的场景
即点击会触发非当前层的点击事件。
有了以上的基础,我们就可以理解为什么会出现点击穿透现象了。我们经常会看到“弹窗/浮层”这种东西,我做个了个demo。
整个容器里有一个底层元素的div,和一个弹出层div,为了让弹出层有模态框的效果,我又加了一个遮罩层。
<div class="container"> <div id="underLayer">底层元素</div> <div id="popupLayer"> <div class="layer-title">弹出层</div> <div class="layer-action"> <button class="btn" id="closePopup">关闭</button> </div> </div> </div> <div id="bgMask"></div> |
然后为底层元素绑定 click 事件,而弹出层的关闭按钮绑定 tap 事件。
$('#closePopup').on('tap', function(e){ $('#popupLayer').hide(); $('#bgMask').hide(); }); $('#underLayer').on('click', function(){ alert('underLayer clicked'); }); |
点击关闭按钮,touchend首先触发tap,弹出层和遮罩就被隐藏了。touchend后继续等待300ms发现没有其他行为了,则继续触发click,由于这时弹出层已经消失,所以当前click事件的target就在底层元素上,于是就alert内容。整个事件触发过程为 touchend -> tap -> click。
而由于click事件的滞后性(300ms),在这300ms内上层元素隐藏或消失了,下层同样位置的DOM元素触发了click事件(如果是input框则会触发focus事件),看起来就像点击的target“穿透”到下层去了。
结合Zepto源码的解释
zepto中的 tap 通过兼听绑定在 document 上的 touch 事件来完成 tap 事件的模拟的,是通过事件冒泡实现的。在点击完成时(touchstart / touchend)的 tap 事件需要冒泡到 document 上才会触发。而在冒泡到 document 之前,手指接触和离开屏幕(touchstart / touchend)是会触发 click 事件的。
因为 click 事件有延迟(大概是300ms,为了实现safari的双击事件的设计),所以在执行完 tap 事件之后,弹出层立马就隐藏了,此时 click 事件还在延迟的 300ms 之中。当 300ms 到来的时候,click 到的其实是隐藏元素下方的元素。
如果正下方的元素有绑定 click 事件,此时便会触发,如果没有绑定 click 事件的话就当没发生。如果正下方的是 input 输入框(或是 select / radio / checkbox),点击默认 focus 而弹出输入键盘,也就出现了上面的“点透”现象。
穿透的解决办法
穿透的原因其实就是tap事件先于click事件300ms执行
1. 遮挡
我们可以动态地在触摸位置生成一个透明的元素,这样当上层元素消失而延迟的click来到时,它点击到的是那个透明的元素,也不会“穿透”到底下。在一定的timeout后再将生成的透明元素移除。具体可见demo
2. pointer-events
pointer-events
是CSS3中的属性,它有很多取值,有用的主要是auto
和none
,其他属性值为SVG服务。
关于使用 pointer-events 后的事件冒泡,有人做了个实验,见代码
因此解决“穿透”的办法就很简单,对下面的元素设置pointer-eventsdemo如下
$('#closePopup').on('tap', function(e){ $('#popupLayer').hide(); $('#bgMask').hide(); $('#underLayer').css('pointer-events', 'none'); setTimeout(function(){ $('#underLayer').css('pointer-events', 'auto'); }, 400); }); |
3. fastclick
使用fastclick库,其实现思路是,会通过DOM自定义事件立即出发模拟一个click事件,并把浏览器在300ms之后真正的click事件阻止掉(参看源码 164-173 行),用 touchend 模拟快速点击行为(参看源码 521-610 行)。
window.addEventListener("load", function () { |
从此所有点击事件都使用click来绑定
,不会出现“穿透”的问题,并且没有300ms的延迟。解决穿透的demo
有人(叶小钗)对事件机制做了详细的剖析,循循善诱,并剖析了fastclick的源码以自己模拟事件的创建。请看这篇文章,看完后一定会对移动端的事件有更深的了解
- 注意点: 框架必须在前面调用, 并且所有的元素都被注册了fastclick中的事件, 以后所有的click事件都是fastclick的click事件
4. 延迟
方法一:延时动画
由于 click 事件的滞后性,在这段时间内原来点击的元素消失了,于是便“穿透”了。因此我们顺着这个思路就想到,可以给元素的消失做一个fade效果,类似jQuery里的fadeOut
,并设置动画duration大于300ms,这样当延迟的 click 触发时,就不会“穿透”到下方的元素了。
同样的道理,不用延时动画,
方法二:对tap做延迟
tap(ele, function () { |
参考资料
zepto学习(二)之tap事件以及tap事件点透处理的更多相关文章
- 前端学习(二十三)DOM操作,事件(笔记)
javascript 组成部分 1.ECMAScript javascript的核心解释器 2.DOM Document Object Modle 文 ...
- 【zepto学习笔记03】事件机制
前言 我们今天直接进入事件相关的学习,因为近期可能会改到里面的代码就zepto来说,我认为最重要的就是选择器与事件相关了,随着浏览器升级,选择器简单了,而事件相关仍然是核心,今天我们就来学习学习 ze ...
- 移动端tap与click的区别 && 点透事件
移动端的问题 移动端的主要问题是click会有300ms的延迟,主要原因是苹果手机在设计时,考虑到用户在浏览网页时需要放大,所以,在用户点击的300ms之后,才触发click,如果300ms之内还有c ...
- 移动端tap或touch类型事件的点透问题认识
1.什么是点透? 举例说明:下图B元素是黄色方块,B元素中包含了C元素,C元素是一个a链接,本身自带click事件按,然后又一个半透明的粉色元素A遮盖在B元素上(看图中A元素是覆盖在B元素上的,不然B ...
- 背水一战 Windows 10 (68) - 控件(控件基类): UIElement - Pointer 相关事件, Tap 相关事件, Key 相关事件, Focus 相关事件
[源码下载] 背水一战 Windows 10 (68) - 控件(控件基类): UIElement - Pointer 相关事件, Tap 相关事件, Key 相关事件, Focus 相关事件 作者: ...
- HTML5触摸事件演化tap事件
触摸事件是移动浏览器特有的HTML5事件,虽然click事件在pc和移动端更通用,但是在移动端会出现300ms延迟,较为影响用户体验,300ms延迟来自判断双击和长按,因为只有默认等待时间结束以确定没 ...
- appium+python自动化37-adb shell模拟点击事件(input tap)
前言 appium有时候定位一个元素很难定位到,或者说明明定位到这个元素了,却无法点击,这个时候该怎么办呢? 求助大神是没用的,点击不了就是点击不了,appium不是万能的,这个时候应该转换思路,换其 ...
- appium+python自动化-adb shell模拟点击事件(input tap)
前言 appium有时候定位一个元素很难定位到,或者说明明定位到这个元素了,却无法点击,这个时候该怎么办呢? 求助大神是没用的,点击不了就是点击不了,appium不是万能的,这个时候应该转换思路,换其 ...
- 移动端 之 触摸事件、Tap事件和swipe事件
触摸事件 touch是一个事件组,意思不止一个事件,是移动端滑动事件组,touchstart touchmove touchend touchcancel touchstart 当刚刚触摸屏幕的时候触 ...
随机推荐
- Cesium学习系列汇总
内容比较多,完整看完需要大概10分钟,废话不多说,撸起袖子,加油干!!! 1.前言 按照套路,先介绍一下什么是Cesium. Cesium ['siːzɪəm]是JavaScript开源库,通过Ces ...
- Java NIO学习笔记八 Pipe
Java NIO Pipe Java NIO管道是两个线程之间的单向数据连接.Pipe 具有源信道和接受通道.您将数据写入sink通道.然后可以从源通道读取该数据. 这是一个原理的Pipe流程图: J ...
- PowerDesigner设置code和name不联动的方法
按照如下设置即可: 具体步骤:菜单:Tools--General Options--Name to Code mirroring的复选框不要选中.
- python多线程、线程锁
1.python多线程 多线程可以把空闲时间利用起来 比如有两个进程函数 func1.func2,func1函数里使用sleep休眠一定时间,如果使用单线程调用这两个函数,那么会顺序执行这两个函数 也 ...
- IOS上的 Audio Memos SE 如何分享和传输录音到电脑?
Audio Memos SE 是 Audio Memos 的精简版 ,顾名思义就是少了很多实用功能.当初下载这个就是因为广告比较少一些,没有全屏幕的广告. 好了,录了音,想分享和传到电脑要怎么弄呢? ...
- Bean映射工具之Apache BeanUtils VS Spring BeanUtils
背景 在我们实际项目开发过程中,我们经常需要将不同的两个对象实例进行属性复制,从而基于源对象的属性信息进行后续操作,而不改变源对象的属性信息,比如DTO数据传输对象和数据对象DO,我们需要将DO对象进 ...
- Docker存储容易忽略的使用细节
一.Docker容器使用前其实有个非常重要的步骤就是规划好部署的磁盘区域,因为docker容器默认存储的路径是在/var/lib/docker的根目录内,随着使用时间越长部署的内容越多,基本的根目录的 ...
- K/3 Cloud 单据关联查询
销售出库单 下推 销售退货单,如何获知他们的关联关系?T_SAL_OUTSTOCKENTRY 是销售出库单分录T_SAL_RETURNSTOCKENTRY 是销售退货单分录T_SAL_RETURNST ...
- 使用C++11原子量实现自旋锁
一.自旋锁 自旋锁是一种基础的同步原语,用于保障对共享数据的互斥访问.与互斥锁的相比,在获取锁失败的时候不会使得线程阻塞而是一直自旋尝试获取锁.当线程等待自旋锁的时候,CPU不能做其他事情,而是一直处 ...
- vue项目中的父子组件之间的传值。
首先说一下父子组件就是在一个vue文件中引入另一个vue文件,被引入vue文件就是子组件,引入vue文件的vue文件就是父组件.而在父组件中是不能直接调用子组件中的变量值的.下面详细说一下,父子组件之 ...