移动端的touch click事件的理解+点透

移动端在touch上一共有4个事件javascript

touchstart touchmove touchend touchcancel, touchcancel, 通常来讲,它们执行的顺序为 touchstart -> touchmove -> touchend -> touchcancel . 其中touchcancel通常状况下不会触发,也不是这里讨论的焦点;

这里会结合click对上面的事件进行讨论, touch发生在click以前css

先上段代码,直观感觉一下html

<!DOCTYPE html>
<html>
  <head>
    <style type="text/css">
      #level0 {
        /* width: 500px;
        height: 500px; */
      }

      #level1-0 {
        background: red;
        width: 500px;
        height: 500px;
      }

      #level1-1 {
        background: green;
        width: 500px;
        height: 500px;
      }
    </style>
  </head>
  <body>
    <div id="level0">
      <div id="level1-0">
      </div>
      <div id="level1-1">
      </div> 
    </div>
  </body>
  <script type="text/javascript">

    var level10 = document.getElementById("level1-0");

    level10.addEventListener('touchstart', function(e) {
      console.log(1);
    });

    level10.addEventListener('touchmove', function(e) {
      console.log(2);
    });

    level10.addEventListener('touchend', function(e) {
      console.log(3);
    });

    level10.onclick = function() {
      console.log(5);
    }

    document.body.onclick = function() {
      console.log('6');
    }

  </script>
</html>
在红色区域点击会出现什么效果呢? 出现的是 1 3 5 6, 奇怪了 touchmove 为什么不执行,由于咱们并无移动,也就是说,必须触碰到屏幕上面,并且发生了移动动做,touchmove才执行,如今咱们触碰到,并且手指稍微动一下,发现输出的效果是, 1 2(+) 3, 其中touchmove 可能触发屡次,又奇怪了, click为什么不执行, 由于 click执行的条件是 点击, 并且不移动 因此通常状况下,咱们能够理解成 touchmove和click是相斥的。
咱们知道,当一个用户在点击屏幕的时候,系统会触发touch事件和click事件,touch事件优先处理,touch事件通过 捕获,处理, 冒泡 一系列流程处理完成后, 才回去触发click事件
既然touch事件和click事件有了优先级别,那么能不能在touch阶段取消掉系统触发的click事件呢?固然是能够的,浏览器提供了这样的能力。在touch事件里面,调用e.preventDefault() 就能够阻止本次点击系统触发的click事件,即本次相关的click都不会执行
 
把上面代码稍微加一点
level10.addEventListener('touchstart', function(e) {
      console.log(1);
      e.preventDefault();
});

点击的时候 发现 只有 1 3, 说明click被阻止了,固然在touchend里面加效果也同样,因此 在touch事件里面加 e.preventDefault能够取消系统产生的click事件, 固然不会阻止后面的touch事件。java

用个具体的例子看看 如何解决点透问题

产生点透问题的缘由, 能够先看看代码吧浏览器

<!DOCTYPE html>
<html>
  <head>
    <style type="text/css">
      #level0 {
        /* width: 500px;
        height: 500px; */
        position: relative;
      }

      #level1-0 {
        position: absolute;
        z-index: 1;
        background: red;
        width: 500px;
        height: 500px;
      }

      #level1-1 {
        background: green;
        width: 500px;
        height: 500px;
      }
    </style>
  </head>
  <body>
    <div id="level0">
      <div id="level1-0">
      </div>
      <div id="level1-1">
      </div> 
    </div>
  </body>
  <script type="text/javascript">

    var level10 = document.getElementById("level1-0");
    var level11 = document.getElementById("level1-1");


    level10.addEventListener('touchstart', function(e) {
      level10.style.display = 'none';
    });

    level11.onclick = function() {
      console.log('level11莫名被点击了');
    }

  </script
</html>
原本是 level1-0 和 level1-1是兄弟节点,即他们之间不会发生什么 事件传递, 目前level1-0至关于一个覆盖层,覆盖在level1-1上面, 按理说点击 level1-0的时候,level1-0会阻挡全部的事件,事件不会传递给level1-1,当点击level1-0的时候,实际上level1-1也发生了点击事件,即上面的输出结果为level1-0消失, 输出 level11莫名被点击了, 这就是点透
点透发生的条件:
  1. A 和 B不是后代继承关系(若是是后代继承关系的话,就直接是冒泡子类的话题了)
  2. A发生touch, A touch后当即消失, B事件绑定click
  3. A z-index大于B,即A显示在B浮层之上
点透发生的理由: 当手指触摸到屏幕的时候,系统生成两个事件,一个是touch 一个是click,touch先执行,touch执行完成后,A从文档树上面消失了,并且因为移动端click还有延迟200-300ms的关系,当系统要触发click的时候,发如今用户点击的位置上面,目前离用户最近的元素是B,因此就直接把click事件做用在B元素上面了.
那如何才能解决点透问题呢? 还记得我以前说过么,系统提供了先触发的touch事件去取消系统生成的click事件,因此只要在touch事件的某个处理函数中 执行 e.preverDefault便可, 通常咱们在touchend中执行
在上面代码中,加上这句就完美解决了
level10.addEventListener('touchend', function(e) {
    e.preventDefault();
});

固然点透问题,还有其余的解决方法,关键是 要么是需求本次系统生成的click事件,要么是当系统触发click的时候,当前的触发touch的那个dom节点还存在。好比将其一延迟3s在关闭dom

setTimeout(() => {
        level10.style.display = 'none';
}, 300);
相关文章
相关标签/搜索