一、指针事件(Pointer Events)是一种用于处理来自各种输入设备(例如鼠标、触控笔和触摸屏等)的输入信息的现代化解决方案。
指针事件简史
指针事件的由来
一、很早以前,只存在鼠标事件。
1、触屏设备(手机、平板电脑)普及后,为了使现有的脚本仍能正常工作,它们生成(现在仍生成)鼠标事件。如,轻触屏幕就会生成mousedown事件。因此,触屏设备可以很好地与网页配合使用。
2、触摸设备比鼠标具有更多功能。如,我们可以同时触控多点(多点触控)。然而,鼠标事件并没有相关属性来处理这种多点触控。
二、因此,引入了触摸事件。如touchstart、touchend、touchmove,它们具有特定于触摸的属性。
1、不过这还不够完美,因为很多其他输入设备(如触控笔)都有自己的特性。而且同时维护两份分别处理鼠标事件和触摸事件的代码,显得有些笨重。
三、为了解决这些问题,人们引入了全新的规范“指针事件”。它为各种指标输入设备提供了一套统一的事件。
兼容性
一、20201114:目前,各大浏览器都已经支持了Pointer Events Level 2标准。
二、除非代码需要兼容旧版本的浏览器,如IE10或Safari12或更低的版本,否则无需继续使用鼠标事件或触摸事件,我们可以使用指针事件。这样,代码就能在触摸设备和鼠标设备上都能正常使用了。
1、针对这些老式浏览器,也可以通过polyfill来让它们支持指针事件。
指针事件类型
一、见:https://www.yuque.com/tqpuuk/yrrefz/pxdwgl
二、代码中用pointer
1、替换后,程序对触屏设备的支持会“魔法般”提升。
2、可能需要在CSS中的某些地方添加touch-action: none。
事件:pintercancel
一、pointercancel事件将会在一个正处于活跃状态的指针交互由于某些原因被中断时触发。也就是在这个事件之后,该指针就不会继续触发更多事件了。
1、导致指针终端的可能原因
(1)指针设备硬件在物理层面上被禁用。
(2)设备方向选择(例如给平板转了个方向)
(3)浏览器打算自行处理这一交互,比如将其看做是一个专门的鼠标手势或缩放操作等。
用指针事件来实现拖放
一、实现一个像“鼠标拖放事件”中提到的对球的拖放操作。
二、用户的操作流程和对应的事件如下
1、用户按住了一张图片,开始拖拽
(1)pointerdown事件触发
2、用户开始移动指针(从而拖动图片)
(1)pointermove事件触发,可能触发多次。
二、1、意外:浏览器有自己的原生的图片拖放操作,接管了之前的拖放过程,于是触发了pointercancel事件。
(1)现在拖放图片的操作由浏览器自行事件。用户甚至可能会把图片拖出浏览器,放进他们的邮件程序或文件管理器。
(2)我们不会再得到pointermove事件了。
2、期望:事件按照我们预期的方式触发,浏览器不会劫持拖放过程,也不会触发pointercancel事件。并且代码对鼠标和触控设备都有效。
3、解决:需要阻止浏览器的默认行为来防止pointercancel触发。
(1)需要做两件事
①阻止原生的拖放操作发生
ball.ondragstart = function() {
return false;
}
② 对于触屏设备,还有其他和触摸相关的浏览器行为(除了拖放)。为了避免它们所引发的问题,可以用css来阻止它们;
#ball {
touch-action: none;
}
指针捕获事件
一、指针捕获事件:
1、gotpointercapture 会在一个元素使用 setPointerCapture 来启用捕获后触发。
2、lostpointercapture 会在捕获被释放后触发:其触发可能是由于 releasePointerCapture 的显式调用,或是 pointerup/pointercancel 事件触发后的自动调用。
指针捕获
一、指针捕获(Pointer capturing)是针对指针事件的一个特性。
1、主要的方法:elem.setPointerCaputre(pointerId)
(1)将给定的pinterId绑定到elem。在调用之后,所有具有相同pointerId的指针事件都将elem作为目标(就像事件发生在elem一样),无论这些elem在文档中的实际位置是什么。
(2)换句话说,elem.setPointerCapture(pointerId)将所有具有给定pointerId的后续事件重新定位到elem。
2、绑定将会在以下情况被移除
(1)当pointerup或pointercancel事件出现时,绑定会被自动地移除。
(2)当elem被从文档中移除后,绑定会被自动地移除。
(3)当elem.releasePointerCapture(pointerId)被调用,绑定会被移除。
二、指针捕获可以被用于简化拖放类的操作。
自定义滑动条
一、创建一个带有条形图的,并且在其内部有一个“滑块”(thumb)的滑动条元素。
1、效果:
(1)用户按下滑动条的滑块thumb: pionterdown事件触发。
(2)然后用户移动指针:pointermove事件触发,我们随之移动thumb
二、移动过程中:
1、问题:在指针的移动过程中,指针可能会离开滑动条的thumb:移动到thumb之上或之下的位置
2、期望:thumb应该严格控制在水平方向上移动,并与指环保持对齐。
3、解决
(1)解决方案1:跟踪指针的所有移动,包括指针移动到thumb之上或之下的位置时。所以在整个文档document上分配ointermove事件处理程序。
① 问题:指针在文档周围的移动可能会引起副作用,触发其他事件处理程序,而这些事件处理程序与滑动条完全无关。
(2)解决方案2:指针捕获提供了一种将pointermove绑定到thumb并避免其他此类问题发生的方式
① 我们可以在pointerdown事件的处理程序中调用thumb.setPointerCapture(event.pointerId)
② 在pointerup /cancel之前发生的所有指针事件都会被重定向到thumb上。
③ 当pointerup发生时(拖动完成),绑定会被自动移除。
④ 这样即使用户在整个文档上移动指针,事件处理程序也将仅在thumb上被调用。
⑤ 事件对象的坐标属性,如clientX / clientY仍将是正确的:捕获仅影响target / currentTarget
三、主要代码
thumb.onpointerdown = function(event) {
// 把所有指针事件(pointerup 之前发生的)重定向到 thumb
thumb.setPointerCapture(event.pointerId);
};
thumb.onpointermove = function(event) {
// 移动滑动条:在 thumb 上监听即可,因为所有指针事件都被重定向到了 thumb
let newLeft = event.clientX - slider.getBoundingClientRect().left;
thumb.style.left = newLeft + 'px';
};
// 注意:无需调用 thumb.releasePointerCapture,
// 它会在 pointerup 时自动调用
指针捕获的好处
一、代码变得更简洁,不再需要在整个documnet上添加/移除处理程序。绑定会被自动释放。
二、如果文档中有任何pointermove处理程序,则在用户拖放滚动条时,它们不会因指针的移动被意外地触发。
指针事件属性
一、指针事件具备和鼠标事件完全相同的属性,包括clientX / Y和target等,以及一些其他属性。
1、ponterId:触发当前事件的指针唯一标识符。
(1)浏览器生成的。使我们能够处理多指针的情况,如带有触控笔和多点触控功能的触摸屏。
2、pointerType:指针的设备类型。
(1)必须为字符串,可以是mouse、pen、touch.
(2)我们使用这个属性来针对不同类型的指针输入做出不同响应。
3、isPrimary:当指针为首要指针(多点触控时按下的第一根手指)时为true。
二、有些指针设备会测量接触面积和点按压力(如一根手指压在触屏上),对于这种情况可以使用以下属性(20201114:大多数设备不支持这些属性):
1、width —— 指针(例如手指)接触设备的区域的宽度。
(1)对于不支持的设备(如鼠标),这个值总是 1。
2、height —— 指针(例如手指)接触设备的区域的长度。
(1)对于不支持的设备,这个值总是 1。
3、pressure —— 触摸压力,是一个介于 0 到 1 之间的浮点数。
(1)对于不支持压力检测的设备,这个值总是 0.5(按下时)或 0。
4、tangentialPressure —— 归一化后的切向压力(tangential pressure)。
5、tiltX, tiltY, twist —— 针对触摸笔的几个属性,用于描述笔和屏幕表面的相对位置。
多点触控
一、多点触控(用户在手机或平板上同时点击若干个位置,或执行特殊手势)是鼠标事件完全不支持的功能之一。
二、指针事件使我们能够通过pointerId和isPrimary属性的帮助,能够处理多点冲。
三、当用户一根手指触控触摸屏的某个位置,然后将另一根手指放在该触摸屏的其他位置时,会发生以下情况
1、第一个手指触摸
(1)pointrdown事件触发,isPrimary = true,并且被指派了一个pointerId
2、第二个和后续的更多个手指触摸(假设第一个手指仍在触摸)
(1)pointerdown事件触发,isPrimary = false,并且每个触摸都被指派了不同的pointerId。
四、利用pointerId,我们可以追踪多根正在触摸屏幕的手指。当用户移动或抬起某根手指时,我们会得到和pointerdown事件具有相同pointerId的pointermove或pointerup事件。