真的了解FastClick吗?:https://www.cnblogs.com/ylweb/p/10549040.html
你真的了解FastClick吗?
前段时间在做公司官网手机端菜单部分的时候,遇到一些很诡异的点击问题。比如菜单点击无效/双击才有效、在手指滑动的时候会触发点击事件、以及同样的事件处理在微信跟浏览器会有不一样的表现等等,这些问题我一直试图用一些移动端事件的hack来解决,到最后还是有两个问题没有解决掉。后来意识到可能是引入的插件导致的事件冲突引起,因为一直都在全局引入了fastclick,以及最初偷懒引入的一个菜单功能插件(插件中有引入iScroll)。经过排查最后得出结论是fastclick与插件 冲突所致,只能去除插件重写菜单功能。而这个小插曲也让我有兴趣阅读一下它的源码来深究一下fastclick到底做了什么?
FastClick的使用场景及背景:
- 移动端的开发经常需要监听用户的双击行为,事件的发生顺序是这样的:touchstart---touchmove---touchend,然后大约过300ms触发click事件,用来判断是否有双击事件。
- 在混合使用touch与click时,会导致点击穿透!(此处不展开讨论)
- FastClick的思路就是利用touch来模拟tap(触碰),如果认为是一次有效的tap,则在touchend时立即模拟一个click事件,分发到事件源(相当于主动触发一次click),同时阻止掉浏览器300ms后产生的click。自然也不存在点击穿透的问题。
众所周知的FastClick用法:
Javascript原生
if ('addEventListener' in document) {
document.addEventListener('DOMContentLoaded', function() {
FastClick.attach(document.body);
}, false);
}
jQuery
$(function() {
FastClick.attach(document.body);
});
类似Common JS的模块系统方式
var attachFastClick = require('fastclick');
attachFastClick(document.body);
needsclick
对于页面上不需要使用fastclick来立刻触发点击事件的元素在元素标签的class上添加needsclick
不需要使用fastclick的情况
-
PC端,FastClick只在移动端监听;
-
Android版Chrome 32+浏览器,如果设置viewport meta的值为width=device-width,这种情况下浏览器会马上出发点击事件,不会延迟300毫秒。
<meta name="viewport" content="width=device-width, initial-scale=1">
- 所有版本的Android Chrome浏览器,如果设置viewport meta的值有user-scalable=no,浏览器也是会立即触发点击事件。
- IE11+浏览器设置了css的属性touch-action: manipulation,它会在某些标签(a,button等)禁止双击事件,IE10的为-ms-touch-action: manipulation
FastClick的实现原理
Fastclick的源码中除了对旧版本浏览器的polyfill以及特殊版本浏览器的的bug解决,主要绑定了以下原型方法:
/*构造函数*/
function FastClick(layer, options)
/*判断是否需要浏览器原生的click事件(针对一些特殊元素比如表单)*/
FastClick.prototype.needsClick = function(target)
/*判断给定元素是否需要通过合成click事件来模拟聚焦*/
FastClick.prototype.needsFocus = function(target)
/*合成click事件并在指定元素上触发*/
FastClick.prototype.sendClick = function(targetElement, event)
/* touchstart */
FastClick.prototype.onTouchStart = function(event)
/* touchmove*/
FastClick.prototype.onTouchMove = function(event)
/* touchend*/
FastClick.prototype.onTouchEnd = function(event)
/*判断这次tap是否有效*/
FastClick.prototype.onMouse = function(event)
/*click handler 捕获阶段监听*/
FastClick.prototype.onClick = function(event)
/*移出fastlick事件绑定*/
FastClick.prototype.destroy = function()
/*调用FastClick*/