乐趣区

关于javascript:5分钟搞懂FastClick原理解析

为什么要用 FastClick

在挪动端 H5 开发过程中,对于点触可能会遇到如下两个问题:

  • 手动点击与真正触发 click 事件会存在 300ms 的提早
  • 点击穿透问题(点击行为会穿透元素触发非父子关系元素的事件)

提早的存在时因为浏览器想晓得你 是否在进行双击 操作;而点击穿透是因为 300ms 提早触发时的副作用。

原理过程

  // 业务代码
  var $test = document.getElementById('test')
  $test.addEventListener('click', function () {console.log('1 click')
  })

  // FastClick 简略实现
  var targetElement = null
  document.body.addEventListener('touchstart', function () {
    // 关键点 1:记录点击的元素
    targetElement = event.target
  })
  document.body.addEventListener('touchend', function (event) {
    // 关键点 2:阻止默认事件(屏蔽之后的 click 事件)event.preventDefault()
    var touch = event.changedTouches[0]
    // 关键点 3:合成 click 事件,并增加可跟踪属性 forwardedTouchEvent
    var clickEvent = document.createEvent('MouseEvents')
    clickEvent.initMouseEvent('click', true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null)
    clickEvent.forwardedTouchEvent = true // 自定义的
    targetElement.dispatchEvent(clickEvent)
  })

原理阐明:
在 document.body 上绑定 touchstart 和 touchend
其中,touchstart 用于记录以后点击元素的 targetElement。
touchend 用于:

  • 组织默认事件(屏蔽之后的 click 事件)
  • 合成 click 事件,并增加可跟踪属性 forwardedTouchEvent
  • 在 targetElement 上触发 click 事件
  • targetElement 上绑定的事件立刻执行!done

点击穿透

比方,页面上有 A 和 B 元素,B 在 A 下面。在 B 元素的 touchstart 事件上注册了一个回调函数,该回调函数的作用是暗藏 B 元素。咱们发现,当咱们点击 B 元素,B 元素被暗藏了,随后,A 元素触发了 click 事件。

挪动端下面,事件执行程序是:touchstart > touchend > click。而 click 事件有 300ms 提早,浏览器触发了 click 事件,然而此时 B 元素不见了,所以该事件被派发到了 A 元素身上。如果 A 元素是一个链接,那此时页面就会意外地跳转。

其余解决方案

禁用缩放
当 HTML 文档头部蕴含如下 meta 标签时:

<meta name="viewport" content="user-scalable=no">
<meta name="viewport" content="initial-scale=1,maximum-scale=1">

表明这个页面是不可缩放的,那双击缩放的性能就没有意义了,此时浏览器能够禁用默认的双击缩放行为并且去掉 300ms 的点击提早。

这个计划有一个 毛病 ,就是必须通过 齐全禁用缩放 来达到去掉点击提早的目标,然而齐全禁用缩放并不是咱们的初衷,咱们只是想禁掉默认的双击缩放行为,这样就不必期待 300ms 来判断以后操作是否是双击。然而通常状况下,咱们还是心愿页面能通过双指缩放来进行缩放操作,比方放大一张图片,放大一段很小的文字。

退出移动版