click 事件在移动端会有 200-300ms ms 的延迟,主要原因是苹果手机在设计时,考虑到用户在浏览网页时需要放大,所以,在用户点击的 200-300ms 之后,才触发 click,如果 200-300ms 之内还有 click,就会进行放大缩小。
touch 事件是针对触屏手机上的触摸事件。现今大多数触屏手机 webkit 内核提供了 touch 事件的监听,让开发者可以获取用户触摸屏幕时的一些信息。其中包括:touchstart,touchmove,touchend,touchcancel 这四个事件,touchstart touchmove touchend 事件可以类比于 mousedown mouseover mouseup 的触发
tap 事件在移动端,代替 click 作为点击事件,tap 事件被很多框架(如 zepto)封装,来减少这延迟问题, tap 事件不是原生的,所以是封装的,那么具体是如何实现的呢?
<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>
拓展:
点透问题
如果我们在移动端所有的 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 标签上了。