移動端的主要問題是click會有300ms的延遲,主要緣由是蘋果手機在設計時,考慮到用戶在瀏覽網頁時須要放大,因此,在用戶點擊的300ms以後,才觸發click,若是300ms以內還有click,就會進行放大縮小。 html
可是,問題是大部分時候放大、縮小時不須要的,有時開發者也會禁用他們,那麼300ms的延遲就是性能上的損耗的,因此,如何解決這300ms的延遲? 在移動端,最容易想到的就是使用touchend來替代click,可是touchend是存在很大的問題的,由於touchend以前多是touchstart、touchmove,最後纔是touchstart,具體情境多是用戶滑動頁面時,不當心在一個按鈕那裏觸發了touchend,這樣就執行了,可是用戶的本意不是如此。 那麼該怎麼解決呢?瀏覽器
爲了減小這300ms的延遲,tap事件被不少框架(如zepto)封裝,來減小這延遲問題, 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標籤上了。