Pointer events 指针事件

目前绝大多数的 Web 内容都假设用户的指针定点设备为鼠标。然而,近年来的新兴设备支持更多不同方式的指针定点输入,如各类触控笔和触摸屏幕等。这就有必要扩展现存的定点设备事件模型,以有效追踪各类* 指针事件 *。

指针事件 - Pointer events 是一类可以为定点设备所触发的 DOM 事件。它们被用来创建一个可以有效掌握各类输入设备(鼠标、触控笔和单点或多点的手指触摸)的统一的 DOM 事件模型。所谓 指针 是指一个可以明确指向屏幕上某一组坐标的硬件设备。建立这样一个单独的事件模型可以有效的简化 Web 站点与应用所需的工作,同时也便于提供更加一致与良好的用户体验,无需关心不同用户和场景在输入硬件上的差异。另外,对于某些需要处理特定设备的场景,指针事件也定义了一个 pointerType (en-US) 属性用以查看触发事件的设备类型。

这些事件需要能够处理 mouse events 之类较为通用的指针输入( mousedown/pointerdown , mousemove/pointermove , 等)。因此,指针事件的类型,很大程度上类似于当前的鼠标事件类型。

此外,一个指针事件,也同时包含了鼠标事件中所常见的属性(client coordinates, target element, button states,等)以及适用于其他输入设备的新属性:pressure, contact geometry, tilt,等等。实际上, PointerEvent 接口继承了所有 MouseEvent 中的属性,以保障原有为鼠标事件所开发的内容能更加有效的迁移到指针事件。

相关名词

active buttons state

The condition when a pointer has a non-zero value for the 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.

活跃指针 - active pointer

任意* 指针 *输入设备都可以产生事件。一个可以产生后继事件的指针可以被认为是一个活跃指针。例如,一个触摸笔处于压下状态时可以认为是活跃的,因为它接下来的抬起或移动都会产生额外的后继事件。

一个可以检测其表面接触行为的传感设备。通常来说,其所用的传感设备是一个可以感知由某些输入设备(如触控笔、压感笔、手指等)所提供的输入信息的可触摸屏幕。

浏览器用以检测某一指针事件的目标元素的过程。通常来说,这一过程是通过比照出现在文档或屏幕媒介上的指针位置与视觉布局来实现的。

某个呈现形式并不确定的硬件,该硬件可以指向一个(或一组)屏幕上特定坐标。典型的指针输入设备有鼠标、触控笔、手指触控点等。

指针捕捉能够允许某些事件的产生。这些事件在指针将要重新指向一些并非通过命中检测而给定元素时触发。

一个被* 指针 *所触发 DOM 事件。

相关接口

首要的接口为 PointerEvent 接口,该接口由一个构造函数 constructor (en-US) 加上一些事件类型以及相应全局事件的处理方法构成。

标准中还包括一些对于 Element Navigator 接口的扩展。接下来的每个部分包含了对于各个接口与属性的简单说明。

PointerEvent 接口

PointerEvent 接口扩展了 MouseEvent 接口,并含有以下属性(这些属性的可写属性全部为 只读 )。

  • pointerId (en-US) - 对于某个由指针引起的事件的唯一标识。
  • width (en-US) - 以 CSS 像素计数的宽度属性,取决于指针的接触面的几何构成。
  • height (en-US) - 以 CSS 像素计数的高度属性,取决于指针的接触面的几何构成。
  • pressure (en-US) - 规范化后的指针输入的压力值,取值范围为 0 到 1,0 代表硬件可检测到的压力最小值,1 代表最大值。
  • tangentialPressure (en-US) The normalized tangential pressure of the pointer input (also known as barrel pressure or cylinder stress) in the range -1 to 1 , where 0 is the neutral position of the control.
  • tiltX (en-US) - the plane angle (in degrees, in the range of -90 to 90) between the Y-Z plane and the plane containing both the transducer (e.g. pen stylus) axis and the Y axis.
  • tiltY (en-US) - the plane angle (in degrees, in the range of -90 to 90) between the X-Z plane and the plane containing both the transducer (e.g. pen stylus) axis and the X axis.
  • twist (en-US) The clockwise rotation of the pointer (e.g. pen stylus) around its major axis in degrees, with a value in the range 0 to 359 .
  • pointerType (en-US) - 表明引发该事件的设备类型(鼠标/笔/触摸等)。
  • isPrimary (en-US) - 表示该指针是否为该类型指针中的首选指针。
  • 事件类型与全局事件处理

    指针事件有始终不同的事件类型,其中其中在鼠标事件中有相对应的语义话表示 ( down, up, move, over, out, enter, leave )。以下是每个事件类型及所对应的 Global Event Handler 的基本介绍。

    pointerenter 当定点设备进入某个元素或其子元素的 命中检测 范围时,或做为某一类不支悬停(hover)状态的设备所触发的 poinerdown 事件的后续事件时所触发。(详情可见 pointerdown 事件类型)。 pointerdown 当某指针得以激活时触发。 pointermove 当某指针改变其坐标时触发。 pointerup 当某指针不再活跃时触发。 pointercancel 当浏览器认为某指针不会再生成新的后续事件时触发(例如某设备不再活跃) pointerout 可能由若干原因触发该事件,包括:定位设备移出了某 命中检测 的边界;不支持悬浮状态的设备发生 pointerup 事件(见 pointerup 事件);作为 pointercancel 事件的后续事件(见 pointercancel 事件);当数位板检测到数位笔离开了悬浮区域时。 pointerleave 当定点设备移出某元素的 命中检测 边界时触发。对于笔形设备来说,当数位板检测到笔移出了悬浮范围时触发。 gotpointercapture 当某元素接受到一个指针捕捉时触发。 lostpointercapture 当针对某个指针的指针捕捉得到释放时触发。

    Element 接口扩展

    对于 Element 接口有以下一些扩展:

  • setPointerCapture() - 该方法将为进一步的指针事件设置一个特定的目标元素。
  • releasePointerCapture() (en-US) - 该方法将释放(并停止)之前对于某一特定的指针事件的指针捕捉。
  • 属性 Navigator.maxTouchPoints 被设计用来指明在同一时间点所支持的最大的触摸点数量。

    例子

    该部分包含了一些指针事件接口的一些基本使用案例。

    注册一个事件处理器

    该例子为一个特定元素的每一个事件类型注册了相应的处理器。

    html

    <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

    <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>
    

    确定首选指针

    在很多场景中,可能存在多个指针(比如某设备同时拥有触摸屏和鼠标)或者一个指针设备支持多个接触点(例如支持多点触控的触摸屏)。应用开发时,可以使用 isPrimary (en-US) 属性来识别每类指针的一组指针输入中的主要指针。如果应用仅希望对首选指针提供支持,则可以忽略其他的指针事件。

    对于鼠标来说,只有一个指针输入,所以这一输入将一直是首选指针。对于触摸输入来说,当用户在触摸屏幕,且没有其他活跃指针时,会被认做首选指针。对于压感笔输入来说,当用户的笔触开始接触屏幕或平面,且当时没有其他的活跃笔触在接触屏幕时,该输入将被认作首选指针。

    确定按钮状态

    对于某些指针设备来说,比如鼠标或者压感笔,设备上可能有一个或多个按钮可以同时或依次序按动。比如在某个按钮释放后立刻按下其他按钮。为了确定这些按钮的按压状态,指针事件使用 button buttons MouseEvent 接口中的事件( PointerEvent 继承于此)表明相应的状态。下表提供了各类设备的按钮状态与 button 和 buttons 属性的属性值对应关系。

    设备按钮状态 button buttons

    备注: 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.