指针事件(Pointer Events)是一种用于处理来自各种输入设备(如:鼠标、触控笔、触摸屏等)的输入信息的现代化解决方案
很早以前,只存在鼠标事件
后来,触屏设备开始普及,尤其是手机和平板电脑。为了使现有的脚本仍能正常工作,它们生成(现在仍生成)鼠标事件。例如,轻触屏幕就会生成 mousedown 事件。因此,触摸设备可以很好地与网页配合使用
但是,触摸设备比鼠标具有更多的功能。例如,我们可以同时触控多点(多点触控)。然而,鼠标事件并没有相关属性来处理这些
因此,引入了触摸事件,例如 touchstart、touchend 和 touchmove,它们具有特定于触摸的属性(这里不再赘述这些特性,因为指针事件更加完善)
不过这还是不够完美。因为很多其他输入设备(如触控笔)都有自己的特性。而且同时维护两份分别处理鼠标事件和触摸事件的代码,显得有些笨重了
为了解决这些问题,引入了全新的规范——指针事件。它为各种指针输入设备提供了一套统一的事件
目前,各大主流浏览器已经支持了 Pointer Events Level 2 标准,版本更新的 Pointer Events Level 3 已经发布,并且大多数情况下与 Pointer Events Level 2 兼容
因此,除非你写的代码需要兼容旧版本的浏览器,例如 IE 10 或 Safari 12 或更低的版本,否则无需继续使用鼠标事件或触摸事件,而是使用指针事件
这样,代码就可以在触摸设备和鼠标设备上都能正常工作了
话虽如此,指针事件仍然有一些重要的奇怪特性,应当对它们有所了解以正确使用指针事件,并避免一些意料之外的错误,下文会对它们进行介绍
指针事件的命名方式和鼠标事件类似:
| 指针事件 | 类似的鼠标事件 |
|---|---|
pointerdown |
mousedown |
pointerup |
mouseup |
pointermove |
mousemove |
pointerover |
mouseover |
pointerout |
mouseout |
pointerenter |
mouseenter |
pointerleave |
mouseleave |
pointercancel |
- |
gotpointercapture |
- |
lostpointercapture |
- |
不难发现,每一个 mouse<event> 都有与之相对应的 pointer<event>
pointer<event> 替换 mouse<event>
可以把代码中的 mouse<event> 都替换成 pointer<event>,程序仍然正常兼容鼠标设备
替换之后,程序对触屏设备的支持会“魔法般”地提升。但是,可能需要在 CSS 中的某些地方添加 touch-action: none,见 [[#指针中断]]
pointercancel:一个正处于活跃状态的指针交互由于某些原因被中断时触发。也就是在这个事件之后,该指针就不会继续触发更多事件了
导致指针中断的可能原因如下:
例子:图片拖拽
pointerdown 事件触发pointermove 事件持续触发pointercancel 事件
pointermove 事件了解决:阻止浏览器的默认行为来防止 pointercancel 触发
img.ondragstart = () => falsetouch-action: none 来阻止它们elem.setPointerCapture(pointerId):将给定的 pointerId 绑定到 elem。在调用之后,所有具有相同 pointerId 的指针事件都将 elem 作为目标(就像事件发生在 elem 上一样)
绑定会在以下情况下被移除:
pointerup 或 pointercancel 事件出现时,绑定会被自动地移除elem 被从文档中移除后,绑定会被自动地移除elem.releasePointerCapture(pointerId) 被调用,绑定会被移除相关事件:
gotpointercapture:在一个元素使用 setPointerCapture 来启用捕获后触发lostpointercapture:在捕获被释放后触发(以上几种情况)指针捕获可以被用于简化拖放类的交互,例如滑块:
![[Pasted image 20240430170127.png|500]]
实现逻辑:
thumb —— pointerdown 事件触发pointermove 事件触发
thumb 上thumb 元素,移动到 thumb 之上或之下的位置。而 thumb 应该严格在水平方向上移动,并与指针保持对齐document 上分配 mousemove 事件处理程序不过,这并不是一个没有副作用的解决方案。问题是,指针在文档周围的移动可能会引起副作用:在其他元素上触发事件处理程序(例如 mouseover)并调用其他元素上与滑动条不相关的功能,这不是预期的效果
这就是指针捕获适用的场景:
pointerdown 事件的处理程序中调用 thumb.setPointerCapture(event.pointerId)pointerup/cancel 之前发生的所有指针事件都会被重定向到 thumb 上pointerup 发生时(拖动完成),绑定会被自动移除因此,即使用户在整个文档上移动指针,事件处理程序也将仅在 thumb 上被调用。尽管如此,事件对象的坐标属性,例如 clientX/clientY 仍将是正确的,捕获仅影响 target/currentTarget
![[Pasted image 20240430162214.png]]
PointerEvent 派生于 MouseEvent,拥有所有的 MouseEvent 特性,且增加了:
pointerType: string:指针的设备类型
mouse:鼠标pen:触控笔touch:触摸屏pointerId: number:触发当前事件的指针唯一标识符,用于多点触控isPrimary: boolean:当指针为首要指针(多点触控时按下的第一根手指)时为 true
pointerId 和 isPrimary 即可处理多点触控有些指针设备会测量接触面积和点按压力,可以使用以下属性:
width/height: number:指针(例如手指)接触设备的区域的宽高,单位像素
1pressure: number:归一化后的触摸压力,范围在 [0, 1]
0.5(按下时)或 0tangentialPressure:归一化后的切向压力(也称为桶压或 cylinder stress),范围在 [-1, 1]
tiltX:由输入设备(如手写笔)与 Y 轴构成的平面,和 Y-Z 平面之间的夹角,范围在 [-90, 90]tiltY:由输入设备(如手写笔)与 X 轴构成的平面,和 X-Z 平面之间的夹角,范围在 [-90, 90]twist:输入设备(如手写笔)围绕自身主轴顺时针旋转的角度,取值范围是 [0, 359] 度