Touch穿透

1、前言css

   相信不少移动开发者都有这样一个体会,那就是咱们在移动端点击事件click对比touchend会有延迟,这是为何呢?html

   其实这是由于览器在click后会等待约300ms去判断用户是否有双击行为,手机须要知道用户是否是想双击放大网页内容。若是300ms内没有再一次click,那么就断定这是一次单击行为,因此咱们基本上都用(touchstart/touchend),可是这些事件在执行完以后还会执行一次click事件。(至于具体的缘由这要从JS事件监听机制的根本的讲起,解释起来太麻烦,感兴趣的同窗能够动手了解一下,咱们这里就不作过多说明了)。ide

 

2、touch事件的来源网站

   PC网页上的大部分操做都是用鼠标的,即响应的是鼠标事件,包括mousedown、mouseup、mousemove和click事件。一次点击行为,事件的触发过程为:mousedown -> mouseup -> click 三步。插件

   由于手机上没有鼠标,因此就用触摸事件touch去实现相似的功能。touch事件包含touchstart、touchmove、touchend,注意手机上并无tap事件。手指触发触摸事件的过程为:touchstart -> touchmove -> touchend。htm

   手机上没有鼠标,但不表明手机不能响应mouse事件,实际上是借助touch去触发mouse事件。有人在PC和手机上对事件作了对比实验,以说明手机对touch事件相应速度快于mouse事件。blog

   从上面的图表对比中咱们能够看出在手机上,当咱们手触碰屏幕时,要过300ms左右才会触发mousedown事件,因此click事件在手机上看起来就像慢半拍同样。事件

 

3、点击穿透的场景开发

   点击穿透的现象主要分为四种:input

 

   1.点击蒙层(Mask Layer)上的关闭按钮,蒙层消失后发现触发了按钮下面元素的click事件。
   蒙层的关闭按钮绑定的是touch事件,而按钮下面元素绑定的是click事件,touch事件触发以后,蒙层消失了,300ms后这个点的click事件出发,事件的目标元素天然就变成了按钮下面的元素,由于按钮跟蒙层一块儿消失了。

 

   2.若是按钮下面刚好是一个有href属性的a标签,那么页面就会发生跳转,由于a标签跳转默认是click事件触发,因此穿透原理和上面的彻底相同。

 

   3.若是按钮下面刚好是文本框input或文本域textarea,则文本框或文本域就会获取焦点,穿透原理和上面的相同。

   4.此次没有蒙层,直接点击页内按钮跳转至新页,而后发现新页面中对应位置元素的click事件被触发了。


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

   其余的点击穿透的例子还有不少,我就不一一细说了。

 

4、Touch穿透的解决办法

   1.延迟

   蒙层被点击后延时至少300ms再在完全隐藏掉蒙层显示下层的内容,缺点是隐藏蒙层变慢了,350ms仍是能感受到慢的,可是这种方法只须要针对蒙层作处理就好了,改动很是小,若是要求不高的话,用这个比较省时省力。

 

   2.增长中间蒙层

   咱们还能够动态地在触摸位置生成一个透明的元素,这样当上层元素消失而延迟的click来到时,它点击到的是那个透明的元素,就不会“穿透”到下面去了,而后再在必定的延迟后将生成的透明元素移除。

 

   3.利用pointer-events方法

   pointer-events是CSS3中的属性,它有不少取值,auto | none | visiblepainted | visiblefill | visiblestroke | visible | painted | fill | stroke | all,有用的主要是auto和none,其余属性值为SVG服务。

   当pointer-events取值为auto时,效果与pointer-events属性未指定时的表现效果相同;当取值为none时,元素永远不会成为鼠标事件的目标,可是,当其后代元素的pointer-events属性指定其余值时,鼠标事件能够指向后代元素,在这种状况下,鼠标事件将在捕获或冒泡阶段触发父元素的事件侦听器。

<div class="upbox"></div>
<div class="underbox"></div>
<div class="button"></div>

$('.button').on('touchstart',function(){
  $('.upbox').hide();
  $('.underbox').hide();
  //立刻让它不能点击
  $('.underbox').css('pointer-events','none');
  //由于click事件须要300ms响应,因此咱们时间定义360ms,时间一过又能够正常点击了
  setTimeout(function(){$('.underbox').css('pointer-events','auto')},360);
});

  

   4.只用click

   页面里的点击事件都用click来触发,可是这样的话,页面里的点击交互都将增长300ms延迟,想一想都慢,可是若是交互性要求不高的话能够这么作,强烈不推荐 ,快一点老是好的。

 

   5.使用fastclick插件

   若是不介意多加载几KB的话,可使用fastclick库,其实现思路是:取消 click 事件,用 touchend 模拟快速点击行为,今后全部点击事件都使用click,不会出现“穿透”的问题,而且没有300ms的延迟。不建议使用,由于有人遇到了bug, fastclick 致使click事件触发两次的问题,并且开发者还必须先引入fastclick库,再把页面内全部touch事件都换成click,稍微有点麻烦,并且多引入几KB的文件只是为了解决点透问题不值当,不如用前三种方法中的任一种。

 

5、总结

   除了上面这五种办法外,相信还有其余我本文中未收录的方法,这就须要你们一块儿来探索了,其实遇到问题,第一重要的不是当即着手解决问题,而是找到问题的根源所在,以后针对根源去消灭问题,至于解决问题的方法,一千我的眼中一千个哈姆雷特,你喜欢哪一种,就用那种方法来。

 

此文章主要发布在网站H5案例分享、公众号H5握手和我的博客中,转载请注明出处。

相关文章
相关标签/搜索