首先介紹tap事件:
- tap事件的意義:在移動端,click事件會有300ms延遲,因為瀏覽器通過判斷300ms內是否會繼續點選,來判斷是否縮放網頁。(即雙擊放大網頁的效果有一個300ms的時間來判斷,300ms過去了,才會觸發click事件)
- tap事件的實現:使用瀏覽器預設支援的touch事件來模擬,根據touchstart、touchmove、touchend這三個事件進行模擬tap事件,達到封裝tap事件的效果。下面的程式碼是我做的一個簡易的封裝。
//定義tap函式,傳入需要繫結的元素,和一個回撥函式
function tap(el,callBack){
var startTime = 0;
var maxTime = 250;
var [startX,startY,endX,endY] = [0,0,0,0]; //es6解構賦值
el.addEventListener('touchstart',function(e){
console.log('touchstart');
startTime = Date.now(); //開始觸控的事件
startX = e.touches[0].clientX; //手指在瀏覽器橫座標
startY = e.touches[0].clientY; //手指在瀏覽器縱座標
})
el.addEventListener('touchmove',function(e){
console.log('touchmove');
endX = e.touches[0].clientX; //手指在瀏覽器橫座標
endY = e.touches[0].clientY; //手指在瀏覽器縱座標
})
el.addEventListener('touchend',function(e){
console.log('touchend');
if( (Date.now()-startTime) > maxTime){ //如果超過了最大時間,不觸發tap
console.log('超時了');
return ;
}
//如果移動距離過大,則不是tap事件。為了大家在電腦上能看到效果,這裡設定成了1000,因為在電腦上移動幅度不好控制。如果是在移動端,設定為30就差不多了。
if(Math.abs(endX-startX) > 1000 || Math.abs(endY-startY) > 1000){
return;
}
callBack(e);
})
}
tap(document.documentElement,function(e){
console.log(e);
});
梳理一下:tap事件的順序就是 touchstart -> touchmove -> touchend -> 在touchend中執行回撥
tap點透的原理:
- 常見到有這種應用場景,點選遮罩層,遮罩層消失,露出底部的頁面。當底部的頁面中某個元素繫結了click事件,並且點選遮罩的時候正好點的是該元素的位置,會發現該元素的click事件被觸發了。
- click在PC端觸發順序是mousedown -> mousemove -> mouseup -> click這個順序來執行的,在移動端觸發順序是touchstart -> touchmove -> touchend -> click這個順序執行。因為在touchend的時候我們的遮罩已經消失了,所以相當於點選到了底部頁面中的元素。所以底部元素會觸發click事件。
tap點透的解決方案:
- 統一使用tap事件,或者click事件。
- 延遲遮罩層消失的時間,使其超過300ms
- 拿個透明遮罩擋住(不推薦,太笨了,還麻煩)
- 使用fastclick庫