zoukankan      html  css  js  c++  java
  • Touch穿透

    一、前言

       相信很多移动开发者都有这样一个体会,那就是我们在移动端点击事件click对比touchend会有延迟,这是为什么呢?

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

    二、touch事件的来源

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

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

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

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

    三、点击穿透的场景

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

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

       2.如果按钮下面恰好是一个有href属性的a标签,那么页面就会发生跳转,因为a标签跳转默认是click事件触发,所以穿透原理和上面的完全相同。

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

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


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

       其他的点击穿透的例子还有很多,我就不一一细说了。

    四、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的文件只是为了解决点透问题不值当,不如用前三种方法中的任一种。

    五、总结

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

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

  • 相关阅读:
    (分享)视频压缩Free Video Compressor 汉化版/中文版【全网唯一】
    (分享)根据IP获取地理位置(百度API)
    易语言5.6 精简破解版[Ctoo]
    性能测试---流程篇
    性能测试--系统资源配置篇
    结合sqlmap进行sql注入过程
    MySQL使用记录
    Oracle创表操作记录
    Oracle常用函数记录
    Oracle使用记录
  • 原文地址:https://www.cnblogs.com/daipianpian/p/8879986.html
Copyright © 2011-2022 走看看