指针事件

122 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天,点击查看活动详情

指针事件(Pointer Events)是一种用于处理来自各种输入设备(例如鼠标、触控笔和触摸屏等)的输入信息的现代化解决方案。

一段简史

让我们先做一个简短的概览,以便你对指针事件及其在其它事件类型中所处位置有个粗略认识。

  • 很早以前,只存在鼠标事件。

    后来,触屏设备开始普及,尤其是手机和平板电脑。为了使现有的脚本仍能正常工作,它们生成(现在仍生成)鼠标事件。例如,轻触屏幕就会生成 mousedown 事件。因此,触摸设备可以很好地与网页配合使用。

    但是,触摸设备比鼠标具有更多的功能。例如,我们可以同时触控多点(多点触控)。然而,鼠标事件并没有相关属性来处理这种多点触控。

  • 因此,引入了触摸事件,例如 touchstarttouchend 和 touchmove,它们具有特定于触摸的属性(这里不再赘述这些特性,因为指针事件更加完善)。

    不过这还是不够完美。因为很多其他输入设备(如触控笔)都有自己的特性。而且同时维护两份分别处理鼠标事件和触摸事件的代码,显得有些笨重了。

  • 为了解决这些问题,人们引入了全新的规范「指针事件」。它为各种指针输入设备提供了一套统一的事件。

目前,各大主流浏览器已经支持了 Pointer Events Level 2 标准,版本更新的 Pointer Events Level 3 已经发布,并且大多数情况下与 Pointer Events Level 2 兼容。

因此,除非你写的代码需要兼容旧版本的浏览器,例如 IE 10 或 Safari 12 或更低的版本,否则无需继续使用鼠标事件或触摸事件 —— 我们可以使用指针事件。

这样,你的代码就可以在触摸设备和鼠标设备上都能正常工作了。

话虽如此,指针事件仍然有一些重要的奇怪特性,你应当对它们有所了解以正确使用指针事件,并避免一些意料之外的错误。我们将在本文中对它们进行介绍。

指针事件类型

指针事件的命名方式和鼠标事件类似:

指针事件类似的鼠标事件
pointerdownmousedown
pointerupmouseup
pointermovemousemove
pointerovermouseover
pointeroutmouseout
pointerentermouseenter
pointerleavemouseleave
pointercancel-
gotpointercapture-
lostpointercapture-

不难发现,每一个 mouse<event> 都有与之相对应的 pointer<event>。同时还有 3 个额外的事件没有相应的 mouse...,我们会在稍后详细解释它们。

在代码中用 pointer<event> 替换 mouse<event>

我们可以把代码中的 mouse<event> 都替换成 pointer<event>,程序仍然正常兼容鼠标设备。

替换之后,程序对触屏设备的支持会“魔法般”地提升。但是,我们可能需要在 CSS 中的某些地方添加 touch-action: none。我们会在下文的 pointercancel 一节中描述这里面的细节。

指针事件属性

指针事件具备和鼠标事件完全相同的属性,包括 clientX/Y 和 target 等,以及一些其他属性:

  • pointerId —— 触发当前事件的指针唯一标识符。

    浏览器生成的。使我们能够处理多指针的情况,例如带有触控笔和多点触控功能的触摸屏(下文会有相关示例)。

  • pointerType —— 指针的设备类型。必须为字符串,可以是:“mouse”、“pen” 或 “touch”。

    我们可以使用这个属性来针对不同类型的指针输入做出不同响应。

  • isPrimary —— 当指针为首要指针(多点触控时按下的第一根手指)时为 true

有些指针设备会测量接触面积和点按压力(例如一根手指压在触屏上),对于这种情况可以使用以下属性:

  • width —— 指针(例如手指)接触设备的区域的宽度。对于不支持的设备(如鼠标),这个值总是 1
  • height —— 指针(例如手指)接触设备的区域的长度。对于不支持的设备,这个值总是 1
  • pressure —— 触摸压力,是一个介于 0 到 1 之间的浮点数。对于不支持压力检测的设备,这个值总是 0.5(按下时)或 0
  • tangentialPressure —— 归一化后的切向压力(tangential pressure)。
  • tiltXtiltYtwist —— 针对触摸笔的几个属性,用于描述笔和屏幕表面的相对位置。

大多数设备都不支持这些属性,因此它们很少被使用。如果你需要使用它们,可以在 规范文档 中查看更多有关它们的详细信息。