移动端tap与click的区别 && 点透事件

移动端的问题

移动端的主要问题是click会有300ms的延迟,主要缘由是苹果手机在设计时,考虑到用户在浏览网页时须要放大,因此,在用户点击的300ms以后,才触发click,若是300ms以内还有click,就会进行放大缩小。 html

  可是,问题是大部分时候放大、缩小时不须要的,有时开发者也会禁用他们,那么300ms的延迟就是性能上的损耗的,因此,如何解决这300ms的延迟? 在移动端,最容易想到的就是使用touchend来替代click,可是touchend是存在很大的问题的,由于touchend以前多是touchstart、touchmove,最后才是touchstart,具体情境多是用户滑动页面时,不当心在一个按钮那里触发了touchend,这样就执行了,可是用户的本意不是如此。 那么该怎么解决呢?浏览器

tap事件

为了减小这300ms的延迟,tap事件被不少框架(如zepto)封装,来减小这延迟问题, tap事件不是原生的,因此是封装的,那么具体是如何实现的呢?框架

主要考虑到下面两点:函数

  • 按住的事件不能超过延时时间,由于长时间可能就是浏览器的复制、粘贴等操做了。
  • 不能在页面中移动,移动是不能触发tap事件的。

咱们能够封装以下:性能

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>tap</title>
  <meta name="viewport" content="width=device-width,initial-scale=1">
</head>
<body>
  <button id="btn">按钮</button>
  <script>
    function tap(ele, callback) {
      // 记录开始时间
      var startTime = 0,
      // 控制容许延迟的时间
          delayTime = 200,
      // 记录是否移动,若是移动,则不触发tap事件
          isMove = false;

      // 在touchstart时记录开始的时间
      ele.addEventListener('touchstart', function (e) {
        startTime = Date.now();
      });

      // 若是touchmove事件被触发,则isMove为true
      ele.addEventListener('touchmove', function (e) {
        isMove = true;
      });

      // 若是touchmove事件触发或者中间时间超过了延迟时间,则返回,不然,调用回调函数。
      ele.addEventListener('touchend', function (e) {
        if (isMove || (Date.now() - startTime > delayTime)) {
          return; 
        } else {
          callback(e);
        }
      })
    }

    var btn = document.getElementById('btn');
    tap(btn, function () {
      alert('taped');
    });
  </script>
</body>
</html>

如上,咱们就能够正常使用tap事件而且避免了300ms延迟的产生。spa

点透问题

若是咱们在移动端全部的click都替换为了tap事件,仍是会触发点透问题的,由于实质是: 在同一个z轴上,z-index不一样的两个元素,上面的元素是一个绑定了tap事件的,下面是一个a标签,一旦tap触发,这个元素就会display: none,而从上面的tap能够看出,有touchstart、touchend,因此会300ms以后触发click事件,而z-index已经消失了,因此,触发了下面的a的click事件,注意: 咱们认为a标签默认是绑定了click事件的。而这种现象不是咱们所期待的。设计

解决方案: (1)使用fastclick。 (2)添加一个延迟。code

(1)直接引入fastclick库。htm

window.addEventListener("load", function () {
   FastClick.attach(document.body);
}, false);

这样,就能够成功解决问题了。blog

(2)对于上一个tap作延迟。

tap(ele, function () {
    setTimeout(function () {
       ele.style.display = 'none';
    }, 300); 
})

这样,过了300ms,那么click事件就不会触发在下面的a标签上了。

相关文章
相关标签/搜索