--- title: Pointer events 指针事件 slug: Web/API/Pointer_events tags: - API - Pointer Events - 交互 - 指针事件 translation_of: Web/API/Pointer_events ---
{{DefaultAPISidebar("Pointer Events")}}
目前绝大多数的Web内容都假设用户的指针定点设备为鼠标。然而,近年来的新兴设备支持更多不同方式的指针定点输入,如各类触控笔和触摸屏幕等。这就有必要扩展现存的定点设备事件模型,以有效追踪各类指针事件。
指针事件 - Pointer events 是一类可以为定点设备所触发的DOM事件。它们被用来创建一个可以有效掌握各类输入设备(鼠标、触控笔和单点或多点的手指触摸)的统一的DOM事件模型。所谓 指针 是指一个可以明确指向屏幕上某一组坐标的硬件设备。建立这样一个单独的事件模型可以有效的简化Web站点与应用所需的工作,同时也便于提供更加一致与良好的用户体验,无需关心不同用户和场景在输入硬件上的差异。另外,对于某些需要处理特定设备的场景,指针事件也定义了一个 {{domxref("PointerEvent.pointerType","pointerType")}} 属性用以查看触发事件的设备类型。
这些事件需要能够处理 {{domxref("MouseEvent","mouse events")}} 之类较为通用的指针输入(mousedown/pointerdown
, mousemove/pointermove
, 等)。 因此,指针事件的类型,很大程度上类似于当前的鼠标事件类型。
此外,一个指针事件,也同时包含了鼠标事件中所常见的属性(client coordinates, target element, button states,等)以及适用于其他输入设备的新属性:pressure, contact geometry, tilt, 等等。实际上,{{domxref("PointerEvent")}} 接口继承了所有 {{domxref("MouseEvent","MouseEvent")}} 中的属性,以保障原有为鼠标事件所开发的内容能更加有效的迁移到指针事件。
buttons
property. For example, in the case of a pen, when the pen has physical contact with the digitizer, or at least one button is depressed while hovering.首要的接口为 {{domxref("PointerEvent")}} 接口,该接口由一个构造函数{{domxref("PointerEvent.PointerEvent","constructor")}} 加上一些事件类型以及相应全局事件的处理方法构成。
标准中还包括一些对于 {{domxref("Element")}} 及 {{domxref("Navigator")}} 接口的扩展。接下来的每个部分包含了对于各个接口与属性的简单说明。
{{domxref("PointerEvent")}} 接口扩展了 {{domxref("MouseEvent")}} 接口,并含有以下属性(这些属性的可写属性全部为{{readonlyInline}})。
-1
to 1
, where 0
is the neutral position of the control.0
to 359
.指针事件有始终不同的事件类型,其中其中在鼠标事件中有相对应的语义话表示 (down, up, move, over, out, enter, leave
)。以下是每个事件类型及所对应的{{domxref("GlobalEventHandlers","Global Event Handler")}}的基本介绍。
Event | On Event Handler | Description |
---|---|---|
{{event('pointerover')}} | {{domxref('GlobalEventHandlers.onpointerover','onpointerover')}} | 当定点设备进入某个元素的命中检测 范围时触发。 |
{{event('pointerenter')}} | {{domxref('GlobalEventHandlers.onpointerenter','onpointerenter')}} | 当定点设备进入某个元素或其子元素的命中检测范围时,或做为某一类不支悬停(hover)状态的设备所触发的poinerdown事件的后续事件时所触发。(详情可见 pointerdown事件类型). |
{{event('pointerdown')}} | {{domxref('GlobalEventHandlers.onpointerdown','onpointerdown')}} | 当某指针得以激活时触发。 |
{{event('pointermove')}} | {{domxref('GlobalEventHandlers.onpointermove','onpointermove')}} | 当某指针改变其坐标时触发。 |
{{event('pointerup')}} | {{domxref('GlobalEventHandlers.onpointerup','onpointerup')}} | 当某指针不再活跃时触发。 |
{{event('pointercancel')}} | {{domxref('GlobalEventHandlers.onpointercancel','onpointercancel')}} | 当浏览器认为某指针不会再生成新的后续事件时触发(例如某设备不再活跃) |
{{event('pointerout')}} | {{domxref('GlobalEventHandlers.onpointerout','onpointerout')}} | 可能由若干原因触发该事件,包括:定位设备移出了某命中检测的边界;不支持悬浮状态的设备发生pointerup事件(见pointerup事件); 作为 pointercancel event事件的后续事件(见pointercancel事件);当数位板检测到数位笔离开了悬浮区域时。 |
{{event('pointerleave')}} | {{domxref('GlobalEventHandlers.onpointerleave','onpointerleave')}} | 当定点设备移出某元素的命中检测边界时触发。对于笔形设备来说,当数位板检测到笔移出了悬浮范围时触发。 |
{{event('gotpointercapture')}} | {{domxref('GlobalEventHandlers.ongotpointercapture','ongotpointercapture')}} | 当某元素接受到一个指针捕捉时触发。 |
{{event('lostpointercapture')}} | {{domxref('GlobalEventHandlers.onlostpointercapture','onlostpointercapture')}} | 当针对某个指针的指针捕捉得到释放时触发。 |
对于{{domxref("Element")}}接口有以下一些扩展:
属性 {{domxref("Navigator.maxTouchPoints")}} 被设计用来指明在同一时间点所支持的最大的触摸点数量。
该部分包含了一些指针事件接口的一些基本使用案例。
该例子为一个特定元素的每一个事件类型注册了相应的处理器。
<html> <script> function over_handler(event) { } function enter_handler(event) { } function down_handler(event) { } function move_handler(event) { } function up_handler(event) { } function cancel_handler(event) { } function out_handler(event) { } function leave_handler(event) { } function gotcapture_handler(event) { } function lostcapture_handler(event) { } function init() { var el=document.getElementById("target"); // Register pointer event handlers el.onpointerover = over_handler; el.onpointerenter = enter_handler; el.onpointerdown = down_handler; el.onpointermove = move_handler; el.onpointerup = up_handler; el.onpointercancel = cancel_handler; el.onpointerout = out_handler; el.onpointerleave = leave_handler; el.gotpointercapture = gotcapture_handler; el.lostpointercapture = lostcapture_handler; } </script> <body onload="init();"> <div id="target"> Touch me ... </div> </body> </html>
这一例子展示了如何访问一个触摸事件的所有事件属性。
<html> <script> var id = -1; function process_id(event) { // Process this event based on the event's identifier } function process_mouse(event) { // Process the mouse pointer event } function process_pen(event) { // Process the pen pointer event } function process_touch(event) { // Process the touch pointer event } function process_tilt(tiltX, tiltY) { // Tilt data handler } function process_pressure(pressure) { // Pressure handler } function process_non_primary(event) { // Pressure handler } function down_handler(ev) { // Calculate the touch point's contact area var area = ev.width * ev.height; // Compare cached id with this event's id and process accordingly if (id == ev.identifier) process_id(ev); // Call the appropriate pointer type handler switch (ev.pointerType) { case "mouse": process_mouse(ev); break; case "pen": process_pen(ev); break; case "touch": process_touch(ev); break; default: console.log("pointerType " + ev.pointerType + " is Not suported"); } // Call the tilt handler if (ev.tiltX != 0 && ev.tiltY != 0) process_tilt(ev.tiltX, ev.tiltY); // Call the pressure handler process_pressure(ev.pressure); // If this event is not primary, call the non primary handler if (!ev.isPrimary) process_non_primary(evt); } function init() { var el=document.getElementById("target"); // Register pointerdown handler el.onpointerdown = down_handler; } </script> <body onload="init();"> <div id="target"> Touch me ... </div> </body> </html>
在很多场景中,可能存在多个指针(比如某设备同时拥有触摸屏和鼠标)或者一个指针设备支持多个接触点(例如支持多点触控的触摸屏)。应用开发时,可以使用{{domxref("PointerEvent.isPrimary","isPrimary")}}属性来识别每类指针的一组指针输入中的主要指针。如果应用仅希望对首选指针提供支持,则可以忽略其他的指针事件。
对于鼠标来说,只有一个指针输入,所以这一输入将一直是首选指针。对于触摸输入来说,当用户在触摸屏幕,且没有其他活跃指针时,会被认做首选指针。对于压感笔输入来说,当用户的笔触开始接触屏幕或平面,且当时没有其他的活跃笔触在接触屏幕时,该输入将被认作首选指针。
对于某些指针设备来说,比如鼠标或者压感笔,设备上可能有一个或多个按钮可以同时或依次序按动。比如在某个按钮释放后立刻按下其他按钮。为了确定这些按钮的按压状态,指针事件使用{{domxref("MouseEvent.button","button")}}与 {{domxref("MouseEvent.buttons","buttons")}}等{{domxref("MouseEvent")}}接口中的事件 ({{domxref("PointerEvent")}}继承于此)表明相应的状态。下表提供了各类设备的按钮状态与button和buttons属性的属性值对应关系。
设备按钮状态 | button | buttons |
---|---|---|
自上次事件后,按键、触摸或笔的接触状态没有改变 | -1 | — |
鼠标移动且无按钮被按压 | — | 0 |
鼠标左键、触摸接触、压感笔接触(无额外按钮被按压) | 0 | 1 |
鼠标中键 | 1 | 4 |
鼠标右键、压感笔笔杆按钮被按压 | 2 | 2 |
鼠标X1(前进) | 3 | 8 |
鼠标X2(后退) | 4 | 16 |
压感笔橡皮擦按钮被按压 | 5 |
32 |
Notice: The button
property indicates a change in the state of the button. However, as in the case of touch, when multiple events occur with one event, all of them have the same value.
指针捕捉允许将某一指针事件,重新指向到一个特定元素,而非经由针对其位置进行命中检测所确定的目标元素。指针捕捉可以用来保证某一元素持续接收到指针事件,即使指针设备的接触点已经离开了元素本身(比如滚动时)。
以下例子展示了向某一元素设置指针捕捉的过程:
<html> <script> function downHandler(ev) { var el=document.getElementById("target"); //Element 'target' will receive/capture further events el.setPointerCapture(ev.pointerId); } function init() { var el=document.getElementById("target"); el.onpointerdown = downHandler; } </script> <body onload="init();"> <div id="target"> Touch me ... </div> </body> </html>
以下例子展示了当{{event("pointercancel")}} 事件发生时,一个指针捕捉被释放对的过程。该例子中,浏览器在{{event("pointerup")}}或{{event("pointercancel")}}事件发生时,会自动执行这一释放。
<html> <script> function downHandler(ev) { var el=document.getElementById("target"); // Element "target" will receive/capture further events el.setPointerCapture(ev.pointerId); } function cancelHandler(ev) { var el=document.getElementById("target"); // Release the pointer capture el.releasePointerCapture(ev.pointerId); } function init() { var el=document.getElementById("target"); // Register pointerdown and pointercancel handlers el.onpointerdown = downHandler; el.onpointercancel = cancelHandler; } </script> <body onload="init();"> <div id="target"> Touch me ... </div> </body> </html>
CSS属性{{cssxref("touch-action")}}被用来指明浏览器是否应当对某一区域的触摸事件应用其默认行为(例如放大或旋转等)。这一属性可以被用在所有元素上,除了:不可替换的行内元素(inline elements)、表格行(table rows)、行组(row groups)、表格列(table columns)、列组(column groups)。
属性值auto
意味着浏览器可以自由应用其默认的触摸行为(对于特定区域),属性值none
则会禁止某一区域的浏览器默认触摸行为。 属性值pan-x
和pan-y
表示由某区域开始的触摸操作仅分别产生水平的或垂直的滚动。属性值manipulation
表示希望浏览器认为某元素上的触摸行为仅用于滚动或放大。
在下面的示例中,浏览器对于div
元素的默认触摸响应行为将被禁止。
<html> <body> <div style="touch-action:none;">Can't touch this ... </div> </body> </html>
在下面的示例中,某些button
元素的默认触摸响应行为将被禁止。
button#tiny { touch-action: none; }
在下面的示例中,当target
元素被触摸时,仅允许响应其在水平方向上的滚动。
#target { touch-action: pan-x; }
尽管指针事件接口允许应用程序去为各种指针输入设备创建更佳的用户体验,但事实上,目前的大多数web内容仍然是仅为支持鼠标输入而设计的。因此,即使一个浏览器支持了指针事件,它也仍然需要在这些仅支持鼠标设置网页在不做任何修改的情况下继续对其提供支持。理想情况下,通用的指针模型将使得应用不再需要专门为鼠标输入设计相应。然而,因为浏览器仍必须处理鼠标事件,所以可能仍留存一些需要加以处理的兼容性问题。这一部分包含了一些对于开发者可能有用的关于鼠标事件和指针事件的异同点。
出于对基于鼠标的内容的兼容性考虑,浏览器会将通用的指针事件映射成相应的鼠标事件。 这一事件映射被乘坐兼容性鼠标事件。开发者可以通过取消pointerdown事件相应来阻止某一特定的兼容性鼠标事件的产生,但需要注意以下情况:
这里有一些在使用指针事件时候可以参考的最佳实践:
规范 | 状态 | 注释 |
---|---|---|
{{SpecName('Pointer Events 3')}} | {{Spec2('Pointer Events 3')}} | 为 getCoalescedEvent 和 getPredictedEvents 加入新的 API,新的 pointerrawupdate 事件,额外的 touch-action 属性:pan-left 、pan-right 、pan-up 、pan-down 。 |
{{SpecName('Pointer Events 2')}} | {{Spec2('Pointer Events 2')}} | 加入 hasPointerCapture 方法,澄清更多边界情况和动态场景。 |
{{SpecName('Pointer Events')}} | {{Spec2('Pointer Events')}} | 初始定义 |
{{Compat("api.PointerEvent")}}
在 {{SpecName('Pointer Events 3')}} 规范中,{{cssxref("touch-action", "CSS touch-action")}} 定义了一些新的值,但目前支持这些新值的浏览器实现很有限。