zoukankan      html  css  js  c++  java
  • 移动端的touch click事件的理解+点透

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

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

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

    先上段代码,直观感受一下

    <!DOCTYPE html>
    <html>
      <head>
        <style type="text/css">
          #level0 {
            /*  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事件。

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

    产生点透问题的原因, 可以先看看代码吧

    <!DOCTYPE html>
    <html>
      <head>
        <style type="text/css">
          #level0 {
            /*  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在关闭

    setTimeout(() => {
            level10.style.display = 'none';
    }, 300);
  • 相关阅读:
    MongoDB的查询
    商品订购及货物采购信息系统(代码分析)
    Java连接数据库(mysql,sqlserver)
    开通博客第一天
    Ubuntu下java环境的搭建
    商品订购及货物采购信息系统(需求分析)
    GitHub客户端发布托管代码
    property中copy和strong修饰符的使用指北
    iOS界面间传值
    GPUImage的滤镜功能一览表
  • 原文地址:https://www.cnblogs.com/web-record/p/10280847.html
Copyright © 2011-2022 走看看