玩过移动端web开发的同学应该都了解过,移动端上的click事件都会有300毫秒的延迟,这300毫秒主要是浏览器为了判断你当前的点击时单击还是双击,但有时候为了更快的对用户的操作做出更快的响应,越过这个300毫秒的延迟是有点必要的,FastClick做的就是这件事,这篇文章会理清FastClick的整体思路,分析主要的代码,但不会贴出所有的代码,仅分析主干,由于历史原因,FastClick对旧版本的机型做了很多兼容性适配,例如ios4,这部分代码到现在显然已经没有什么分析的意义了,所以贴出的代码会将这部分代码删除。
首先,我们分析一下总体的实现思路,其实FastClick做的事情很简单,首先判断当前浏览器需不需要使用FastClick,例如桌面浏览器,那就不需要,直接绕过,接着,如果需要,则在click事件中拦截事件,取消所有绑定事件的操作,接着用一系列touch事件(touchstart,touchmove,touchend)来模拟click事件,由于touch事件不会延迟,从而达到绕过300毫秒延迟的效果。
先看看FastClick是如何判断浏览器是否需要FastClick的
FastClick.notNeeded = function(layer) {
var metaViewport;
var chromeVersion;
var blackberryVersion;
var firefoxVersion;
// Devices that don't support touch don't need FastClick
//不支持用于模拟的touchstart事件,无法模拟
if (typeof window.ontouchstart === 'undefined') {
return true;
}
// 探测chome浏览器
chromeVersion = +(/Chrome\/([0-9]+)/.exec(navigator.userAgent) || [,0])[1];
if (chromeVersion) {
//安卓设备
if (deviceIsAndroid) {
metaViewport = document.querySelector('meta[name=viewport]');
if (metaViewport) {
// 安卓下,带有 user-scalable="no" 的 meta 标签的 chrome 是会自动禁用 300ms 延迟的,无需 FastClick
if (metaViewport.content.indexOf('user-scalable=no') !== -1) {
return true;
}
//chome32以上带有 width=device-width的meta标签的也唔需要使用FastClick
if (chromeVersion > 31 && document.documentElement.scrollWidth <= window.outerWidth) {
return true;
}
}
// 桌面设备自然无需使用
} else {
return true;
}
}
//黑莓浏览器,这个。。。了解就好
if (deviceIsBlackBerry10) {
//检测黑莓浏览器
blackberryVersion = navigator.userAgent.match(/Version\/([0-9]*)\.([0-9]*)/);
// 黑莓10.3以上部分可以不适用FastClick
if (blackberryVersion[1] >= 10 && blackberryVersion[2] >= 3) {
metaViewport = document.querySelector('meta[name=viewport]');
if (metaViewport) {
// 跟chome一样
if (metaViewport.content.indexOf('user-scalable=no') !== -1) {
return true;
}
// 跟chome一样
if (document.documentElement.scrollWidth <= window.outerWidth) {
return true;
}
}
}
}
//ie10带有msTouchAction,touchAction相关样式的不需要FastClick
if (layer.style.msTouchAction === 'none' || layer.style.touchAction === 'manipulation') {
return true;
}
//firefox,跟chome差不多
firefoxVersion = +(/Firefox\/([0-9]+)/.exec(navigator.userAgent) || [,0])[1];
if (firefoxVersion >= 27) {
// Firefox 27+ does not have tap delay if the content is not zoomable - https://bugzilla.mozilla.org/show_bug.cgi?id=922896
metaViewport = document.querySelector('meta[name=viewport]');
if (metaViewport && (metaViewport.content.indexOf('user-scalable=no') !== -1 || document.documentElement.scrollWidth <= window.outerWidth)) {
return true;
}
}
//ie11检测,跟ie10一样,只是ie11废弃了msTouchAction,改为touchAction,依旧是检测样式