JS经常使用库解密-FastClick

众所周知,移动端在处理点击事件的时候,会有300毫秒的延迟。偏偏是这300毫秒的延迟,会让人有一种卡顿的体验。javascript

这300毫秒的缘由,在于早期浏览器的实现中,浏览器不知道用户触摸后,到底想作什么,因此故意等待300毫秒,再触发click事件。html

既然咱们已经知道了缘由了,怎么解决呢?java

方案1-粗暴治标法

由于浏览器对click事件的处理,有300ms的延迟,而touchstart几乎是当即执行的,估将全部click事件的监听,改成touchstart事件的监听,便可消除这300ms的延迟。浏览器

但这样反作用也很大,移动端的交互体验全靠触摸,touchstart将会干扰其余交互行为的处理,例如滚动、拖拽等。this

方案2-模拟修复法

既然浏览器有这300ms的延迟,那么咱们来代替浏览器判断,手动触发click事件,这也是fastClick的解决方案。spa

fastClick的核心代码prototype

FastClick.prototype.onTouchEnd = function(event){

  // 一些状态监测代码 

  // 从这里开始,
  if (!this.needsClick(targetElement)) {
    // 若是这不是一个须要使用原生click的元素,则屏蔽原生事件,避免触发两次click
    event.preventDefault(); 
    // 触发一次模拟的click
    this.sendClick(targetElement, event);
  }
}

这里能够看到,FastClick在touchEnd的时候,在符合条件的状况下,主动触发了click事件,这样避免了浏览器默认的300毫秒等待判断。为了防止原生的click被触发,这里还经过event.preventDefault()屏蔽了原生的click事件。code

咱们来看看他是怎么模拟click事件的htm

FastClick.prototype.sendClick = function(targetElement, event) {

  // 这里是一些状态检查逻辑

  // 建立一个鼠标事件
  clickEvent = document.createEvent('MouseEvents');
  // 初始化鼠标事件为click事件
  clickEvent.initMouseEvent(this.determineEventType(targetElement), true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);

  // fastclick的内部变量,用来识别click事件是原生仍是模拟
  clickEvent.forwardedTouchEvent = true;

  // 在目标元素上触发该鼠标事件,
  targetElement.dispatchEvent(clickEvent);

咱们在网上搜索fastClick,大部分都在说他解决了zepto的点击穿透问题,他是怎么解决的呢?就是上面最后一句,他模拟的click事件是在touchEnd获取的真实元素上触发的,而不是经过坐标计算出来的元素。事件

最后,原理虽简单,但仍是建议你们直接用FastClick而不是本身再实现一个。由于,你看他源码里面的注释,有不少特殊状况的补丁的,本身实现一个精简版不免会漏这漏那。

附录

同步发表于个人博客

相关文章
相关标签/搜索