5.touch事件与点击穿透问题

前言

移动端web事件模型不同于PC页面事件, 了解touch事件原理及为什么通过touch触发click事件还有可能存在的一些问题。( 会出现弹出层及页面跳转触发一些问题。)

一、touch事件由来

PC上大部分都是用鼠标操作,响应的是鼠标事件 包括mousedown 、 mouseup 、 mousemoveclick事件, 一次点击行为,事件的触发过程为:

mousedown - > mouseup - > click 三步。

手机上没有鼠标事件,所有使用触摸实现类似功能,touch事件包含 :touchstart 、 touchmove 、touchend 值得注意的手机上没有tap事件,手机触发触摸事件的过程为:

touchstart - > touchmove -> touchend

值得注意在手机触碰屏幕时,会有250ms~300ms 左右才会触发mousedown事件,所以click事件在手机上会有延迟现象。

二、touch事件中可以获取以下参数

参数 含义
touches 屏幕中每根手指信息列表
targetTouches 和touches类似,把同一节点的手指信息过滤掉
changedTouches 响应当前事件的每根手指的信息列表

三、tap是怎么来的

手机上响应click事件会有300ms的延迟, 浏览器在touchend后会等待约300ms 判断用户是否有双击(double tap)行为。如果没有则触发 click事件 ,二双击过程中不适合触发click事件.

tap事件是模拟出来的,可以看下zepto对singleTap事件的处理

// trigger single tap after 250ms of inactivity见源码 136-143 行 可以看出在 touchend 响应 250ms 无操作后,则触发singleTap。

四、点击穿透的场景

使用zepto tap 事件例子:

有个弹出层,下边有其它事件,点击弹出层关闭按钮 测试弹出层会关闭会触发弹出层下边绑定的事件,这是由于 click事件滞后性(300ms) 在这300ms内上层元素隐藏消失了,下层同样位置的DOM触发了click事件(如果是input框则会触发focus事件)看起来就像是target"穿透"到下层去了,使用tap 大多数都会遇到这个坑。 这个事件执行过程: touchend - > tap - > click

五、结合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 而弹出输入键盘,也就出现了上面的“点透”现象。

六、穿透的解决办法

1. 遮挡

由于 click 事件的滞后性,在这段时间内原来点击的元素消失了,于是便“穿透”了。因此我们顺着这个思路就想到,可以给元素的消失做一个fade效果,类似jQuery里的fadeOut,并设置动画duration大于300ms,这样当延迟的 click 触发时,就不会“穿透”到下方的元素了。

同样的道理,不用延时动画,我们还可以动态地在触摸位置生成一个透明的元素,这样当上层元素消失而延迟的click来到时,它点击到的是那个透明的元素,也不会“穿透”到底下。在一定的timeout后再将生成的透明元素移除

2. pointer-events

取值 含义
auto 效果和没有定义 pointer-events 属性相同,鼠标不会穿透当前层。
none 元素不再是鼠标事件的目标,鼠标不再监听当前层而去监听下面的层中的元素。但是如果它的子元素设置了pointer-events为其它值,比如auto,鼠标还是会监听这个子元素的。
$('#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库,其实现思路是,取消 click 事件(参看源码 164-173 行),用 touchend 模拟快速点击行为(参看源码 521-610 行)。

   FastClick.attach(document.body);

例子:


彻底解决tap点透,提升移动端响应速度

你可能感兴趣的:(5.touch事件与点击穿透问题)