移动浏览器原生click事件有300ms的延时,这是浏览器为了区分到底是双击还是单击事件。
(实际上有些移动浏览器不支持双击事件。PC版chrome在手机模式下,当禁止用户双击缩放页面时(即有viewport meta标签时,不管user-scalable为yes或no),双击会触发两次click事件,但并不会触发dblclick事件,当允许用户双击缩放页面时(即没有viewport meta标签时),双击不会触发click事件,也不会触发dblclick事件,而是会缩放页面;在正常模式下(即PC模式),双击会先触发两次click事件,然后再触发一次dblclick事件)
fastclick解决了单击事件的300ms延迟问题,原理大致如下:
touchstart,touchmove,touchend事件是没有延迟的,当touchend事件触发时,如果从touchstart触发到touchend触发的过程中没有移动且时间间隔没有超过界限,那么就执行event.prentDefault()且人为的在目标元素上派发Click事件(targetElement.dispatchEvent(clickEvent),dispatchEvent派发的事件就跟我们在浏览器中实际操作触发的事件一样,能够传播,即有捕获阶段和冒泡阶段)。由于执行了event.prentDefault(),所以会导致浏览器原生的单击和双击事件不会再触发了。
通过上面的讲解,我们可以知道,使用fastclick后,是无法区分单击和双击的,fastclick统统都认为是单击事件,所以我们只能人为地来模拟单击事件和双击事件(300ms内只有一次点击为单击事件,否则就是双击或者多击事件)。
//给$elem元素自定义click事件
function customClick($elem) {
var lastTouch, //上一次touchstart触发的时间
touching, //是否正在触屏
moved, //是否touchmove过
multiClick, //是否单指多击
multiFinger; //是否多指操作
function onTouchStart(event) {
var t = 300,
time = new Date().getTime();
if (event.touches.length !== 1) { //多指操作
multiFinger = true;
} else {
if (lastTouch && time - lastTouch < t) {
//!multiClick && $elem.dblclick(); 双击事件
multiClick = true;
} else {
multiClick = false;
moved = false;
multiFinger = false;
setTimeout(function () {
//没有多指操作过,没有多次点击过,触屏期间没有touchmove过,且现在没有触屏
!multiFinger && !touching && !multiClick && !moved && $elem.clicked();
}, t);
}
}
lastTouch = time;
touching = true;
}
function onTouchEnd(event) {
!event.touches.length && (touching = false);
}
function onTouchMove(event) {
moved = true;
}
$elem.on('touchstart', onTouchStart).on('touchend', onTouchEnd).on('touchmove', onTouchMove);
}