移動端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標籤上了。

相關文章
相關標籤/搜索