美文网首页
探讨移动端点击穿透的问题.

探讨移动端点击穿透的问题.

作者: 人话博客 | 来源:发表于2022-01-20 15:42 被阅读0次

    我们都知道,在有了移动端之后,就多了以 touch 开头的事件类型.

    • touchstart
    • touchmove
    • touchend
    • touchcancel

    为什么浏览器端在本身有了 click 事件时候,还非要针对移动端设置新的 touch 事件呢? click 也可以相应用户点击啊?你管是用户在移动端是用手指点的,还是在PC端是用鼠标点的呢?

    300ms 延迟是怎么回事?

    我相信很多人都知道 300ms,这个在移动端里经常提到的数字,但它到底是什么含义的?

    当在移动端绑定click事件时 .

    <button id="btn">在移动端相应click事件的按钮?</button>
    document.getElmenentById('btn).addEventListener('click', function () {
      console.log('移动端的click事件被触发了')
    }, false)
    

    你会发现click事件也可以执行. 初看之下没有什么问题.

    当你在移动端绑定touch事件时.

    <button id="btn">在移动端相应touch事件的按钮?</button>
    document.getElmenentById('btn).addEventListener('touchstart', function () {
      console.log('移动端的touch事件被触发了')
    }, false)
    

    touch 事件同样会被触发,也没有什么问题.

    当你同时给一个元素绑定上 touch & click 事件时

    <button id="btn">在移动端相应touch事件的按钮?</button>
    document.getElmenentById('btn).addEventListener('click', function () {
      console.log('移动端的click事件被触发了')
    }, false)
    document.getElmenentById('btn).addEventListener('touchstart', function () {
      console.log('移动端的touch事件被触发了')
    }, false)
    

    你会发现:

    • 在PC端,仅会触发 click 事件.舍弃 touch 事件.

    • 在移动端总会先触发 touch 事件,接着在触发 click 事件.

    • 如果你开启了理想视口 (<meta name="viewport" content="width=device-width, initial-scale=1.0">), touchclick 事件触发之间的间隔大致在100ms左右. 根据不同的机型,可能有区别.

      理想视口开启,我的机器延迟在80ms左右
    • 如果你没开启理想视口, touchclick 之间的触发间隔大致在 300ms 左右.(每个机型差异不大)
    没有开启理想视口,延迟300ms左右,各机型差距不大

    结论

    • 移动端同时支持 touchclick 事件.
    • PC端仅支持 click 事件,而舍弃 touch 事件.
    • 移动端总是先触发 touch 在触发 click.
    • 当你没开启理想视口时, touchclick 之间的调用时间差是 300ms
    • 当你开启了理想视口时, touchclick 之间的调用时间差大致在 40-100ms 之间.

    这就是别人口里说的,移动端 300ms 延迟问题的 <span style="color:red;"> ([一半])<span>.

    为什么说是 <span style="color:red;">一半?</span>

    • 因为 addEventListener 本身就可以某个元素注册的某个事件注册多个回调函数.
    • 我们给 btn 注册了两次事件(一次 touch , 一次 click),它两在移动端当然后会全部执行.
    • 只不过是否开启安全视口会影响他两之间的调用延迟.

    点击穿透问题

    • 点击穿透的问题核心是,移动端浏览器,在触发了一个元素的 touch 事件后,会在(<span style="color:red;">20-100ms或者300ms后</span>)接着触发此元素绑定的 click 事件(如果有)
    • 如果没有 click,那就完事大吉,啥也不干.到此结束.
    • 但是如果,绑定 touch 事件的元素式一个[正好]弹窗,在 touch 完之后,[正好]就隐藏消失. 但是后续在<span style="color:red;">20-100ms或者300ms后</span>调用click 这件事情,仍然在进行.
    • 如果正好,弹窗下面有一个元素绑定了click或者本身就有默认的click相应(比如a标签), <span style="color:red">此时也在寻迹click的延迟范围内</span>,那么点击穿透的问题就来了.

    所以,点击穿透问题,是一个天时地利人和都得满足情况下,才会产生的问题.

    • touch元素点击完后消失.
    • 元素后面(视觉上),正好有一个元素绑定了click 或者有默认的click 行为(a标签,表单的submit按钮).
    • 点击穿透问题产生了.

    一个DEMO说明点击穿透问题.

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>02_移动端点击穿透</title>
      <style>
        * {
          margin: 0;
          padding: 0;
        }
    
        a {
          display: block;
          height: 100vh;
          width: 100vm;
          /* background-color: antiquewhite; */
          text-align: center;
          line-height: 80vh;
        }
    
        #mask {
          position: fixed;
          left: 0;
          top: 0;
          width: 100%;
          bottom: 0;
          background-color: rgba(0, 0, 0, 0.2);
          display: flex;
          justify-content: center;
          align-items: center;
        }
    
        .btn {
          width: 200px;
          height: 40px;
          background-color: seagreen;
          color: #fff;
          border: none;
          outline: none;
        }
      </style>
    </head>
    
    <body>
      <a href="https://www.baidu.com">去百度</a>
      <div id="mask">
        <button class="btn">点我关闭</button>
      </div>
    </body>
    <script>
      // 1. 上层touch事件[正好]让元素消失.
      // 2. 下层也[正好]有一个绑定了click,或者有默认click属性的元素(a标签).
      // 3. 当上层元素消失后,就会触发这个下层元素的click事件.
      const btn = document.querySelector('.btn')
      const mask = document.getElementById('mask')
      btn.addEventListener('touchstart', function () {
        mask.style.display = 'none'
      }, false)
    
    </script>
    
    </html>
    

    运行起来,你就会发现,当弹窗消失后,就立马会出发A标签的click事件,从而进入百度.


    点击穿透问题.gif

    点击穿透问题的核心就很清楚了.

    移动端浏览器,在触发了 touch 事件之后,会在某段延迟时间之后,继续触发 click 事件. 这个 click 事件可以触发在之前的元素上.如果之前的元素消失了,就会触发在此元素下面的元素上(视觉上,非结构上)


    点击穿透的问题解决.

    • 你既然是开发移动端事件,那就不要用 click, 全部用 touch 事件( <span style="color:red"> touch事件之间没有点击穿透问题 </span>). 杜绝 touch 在后续延迟时间里 click 的问题.
    • 对于某些没有办法避免的原生 click 事件,比如 A标签, 你可以让弹窗不要立马消失,延迟至少 300ms.这样,即使弹窗消失了,但是因为寻找 click 的时间段已经结束.所以也不会出现问题.
    • 当然还有很多各种各样的解决方案,但核心就一点,不要出现 click. 如果避免不了,就让在找 click 的这段延时里,不让 click 元素暴露出来.

    其实点击穿透问题,一般也就出现在弹窗和点击弹窗立马消失,且弹窗下面正好有click原生事件的元素情况下.
    大多数情况下,你不必去专门考虑点击穿透问题,等遇到了,利用上述原则,去解决就好了.

    相关文章

      网友评论

          本文标题:探讨移动端点击穿透的问题.

          本文链接:https://www.haomeiwen.com/subject/mgvjhrtx.html