移動端tap與click的區別 && 點透事件


移動端的問題

  移動端的主要問題是click會有300ms的延遲,主要原因是蘋果手機在設計時,考慮到用戶在瀏覽網頁時需要放大,所以,在用戶點擊的300ms之后,才觸發click,如果300ms之內還有click,就會進行放大縮小。 

  但是,問題是大部分時候放大、縮小時不需要的,有時開發者也會禁用他們,那么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延遲的產生。

 

 

點透問題

  如果我們在移動端所有的click都替換為了tap事件,還是會觸發點透問題的,因為實質是: 在同一個z軸上,z-index不同的兩個元素,上面的元素是一個綁定了tap事件的,下面是一個a標簽,一旦tap觸發,這個元素就會display: none,而從上面的tap可以看出,有touchstart、touchend,所以會300ms之后觸發click事件,而z-index已經消失了,所以,觸發了下面的a的click事件,注意: 我們認為a標簽默認是綁定了click事件的。而這種現象不是我們所期待的。

  解決方案: (1)使用fastclick。 (2)添加一個延遲。

(1)直接引入fastclick庫。

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

 這樣,就可以成功解決問題了。

 

(2)對於上一個tap做延遲。

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

  這樣,過了300ms,那么click事件就不會觸發在下面的a標簽上了。

 

 

 

一個人可以過孤獨的生活,但一個人不可以過沒有向往的生活。    --- 俞敏洪

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM