指標事件

Baseline 廣泛可用 *

此特性已經十分成熟,可在許多裝置和瀏覽器版本上使用。自 2020 年 7 月以來,它已在各大瀏覽器中可用。

* 此特性的某些部分可能存在不同級別的支援。

如今的許多 Web 內容都假設使用者的指向裝置是滑鼠。然而,由於許多裝置支援其他型別的指向輸入裝置,例如筆/手寫筆和觸控式螢幕,因此需要對現有的指向裝置事件模型進行擴充套件。Pointer Events 解決了這一需求。

Pointer Events 是為指向裝置觸發的 DOM 事件。它們旨在建立一個統一的 DOM 事件模型,以處理滑鼠、筆/手寫筆或觸控(例如一個或多個手指)等指向輸入裝置。

指標(Pointer)是一種與硬體無關的裝置,可以指向螢幕上的特定座標集。擁有一個統一的指標事件模型可以簡化網站和應用程式的建立,並提供良好的使用者體驗,無論使用者使用何種硬體。但是,對於需要裝置特定處理的場景,Pointer Events 定義了一個 pointerType 屬性來檢查產生事件的裝置型別。

處理通用指標輸入所需的事件類似於滑鼠事件mousedown/pointerdownmousemove/pointermove 等)。因此,Pointer 事件型別與滑鼠事件型別有意保持相似。

此外,Pointer 事件除了包含滑鼠事件中常見的屬性(客戶端座標、目標元素、按鈕狀態等)之外,還包含其他形式輸入的新屬性:壓力、接觸幾何、傾斜等。事實上,PointerEvent 介面繼承了所有 MouseEvent 屬性,從而方便內容從滑鼠事件遷移到 Pointer 事件。

術語

活動按鈕狀態

指標buttons 屬性具有非零值時的條件。例如,對於筆,當筆與數字化儀物理接觸時,或者在懸停時至少按下一個按鈕。

活動指標

任何可以產生事件的指標輸入裝置。如果指標仍然可以產生進一步的事件,則認為它是活動的。例如,處於按下狀態的筆被認為是活動的,因為它在筆抬起或移動時可以產生額外的事件。

數字化儀

一種具有可檢測接觸表面的感測裝置。最常見的是,感測裝置是支援觸控的螢幕,可以感應來自筆、手寫筆或手指等輸入裝置的輸入。一些感測裝置可以檢測輸入裝置的近距離,並且該狀態表示為滑鼠懸停。

命中測試

瀏覽器用於確定 Pointer 事件目標元素的過程。通常,這是透過考慮指標的位置以及文件中元素在螢幕媒體上的視覺佈局來確定的。

pointer

一種與硬體無關的輸入裝置表示,可以指向螢幕上的特定座標(或座標集)。指標輸入裝置的示例包括滑鼠、筆/手寫筆和觸控接觸。

指標捕獲

指標捕獲允許將指標的事件重新定向到特定元素,而不是指標位置的正常命中測試結果。有關示例,請參閱捕獲指標

注意:指標捕獲指標鎖定不同,後者物理上阻止指標離開某個區域。

指標事件

指標觸發的 DOM 事件

介面

主要介面是 PointerEvent 介面,它有一個 constructor 以及幾種事件型別和相關的全域性事件處理程式。

該標準還包括對 ElementNavigator 介面的一些擴充套件。

以下小節包含每個介面和屬性的簡短描述。

PointerEvent 介面

PointerEvent 介面擴充套件了 MouseEvent 介面並具有以下屬性。

altitudeAngle 只讀

表示感測器(指標或手寫筆)軸與裝置螢幕的 X-Y 平面之間的角度。

azimuthAngle 只讀

表示 Y-Z 平面與包含感測器(指標或手寫筆)軸和 Y 軸的平面之間的角度。

PointerEvent.persistentDeviceId 只讀

生成 PointerEvent 的指向裝置的唯一識別符號。

pointerId 只讀

導致事件的指標的唯一識別符號。

width 只讀

指標接觸幾何的寬度(X 軸上的大小),以 CSS 畫素為單位。

height 只讀

指標接觸幾何的高度(Y 軸上的大小),以 CSS 畫素為單位。

pressure 只讀

指標輸入的歸一化壓力,範圍為 01,其中 01 分別表示硬體能夠檢測到的最小和最大壓力。

tangentialPressure 只讀

指標輸入的歸一化切向壓力(也稱為桶壓或圓柱應力),範圍為 -11,其中 0 是控制器的中立位置。

tiltX 只讀

Y-Z 平面與包含指標(例如筆手寫筆)軸和 Y 軸的平面之間的平面角(以度為單位,範圍為 -9090)。

tiltY 只讀

X-Z 平面與包含指標(例如筆手寫筆)軸和 X 軸的平面之間的平面角(以度為單位,範圍為 -9090)。

twist 只讀

指標(例如筆手寫筆)圍繞其主軸的順時針旋轉角度,以度為單位,值為 0359

pointerType 只讀

指示導致事件的裝置型別(滑鼠、筆、觸控等)。

isPrimary 只讀

指示此指標是否表示此指標型別的主要指標。

事件型別和全域性事件處理程式

Pointer 事件有十種事件型別,其中七種與它們的滑鼠事件對應項具有相似的語義(downupmoveoveroutenterleave)。

以下是每種事件型別的簡短描述。

Event 描述
pointerover 當指標移入元素的命中測試邊界時觸發。
pointerenter 當指標移入元素或其後代元素的命中測試邊界時觸發,包括由於不支援懸停的裝置(參見 pointerdown)觸發 pointerdown 事件的結果。
pointerdown 當指標變為活動按鈕狀態時觸發。
pointermove 當指標更改座標時觸發。如果指標狀態的更改無法透過其他事件報告,則也使用此事件。
pointerup 當指標不再處於活動按鈕狀態時觸發。
pointercancel 如果瀏覽器斷定指標將不再能夠生成事件(例如,如果相關裝置被停用,或者瀏覽器決定將互動解釋為平移/縮放),則會觸發此事件。有關如何控制此行為的資訊,請參閱下面的touch-action CSS 屬性部分
pointerout 由於多種原因觸發,包括:指標移出元素的命中測試邊界;為不支援懸停的裝置觸發 pointerup 事件(參見 pointerup);在觸發 pointercancel 事件之後(參見 pointercancel);當筆手寫筆離開數字化儀可檢測到的懸停範圍時。
pointerleave 當指標移出元素的命中測試邊界時觸發。對於筆裝置,當手寫筆離開數字化儀可檢測到的懸停範圍時,會觸發此事件。
pointerrawupdate 實驗性 當指標更改任何不觸發 pointerdownpointerup 事件的屬性時觸發。
gotpointercapture 當元素接收到指標捕獲時觸發。
lostpointercapture 為指標釋放指標捕獲後觸發。

元素擴充套件

Element 介面有三個擴充套件

hasPointerCapture()

指示被呼叫的元素是否具有給定指標 ID 標識的指標捕獲。

releasePointerCapture()

釋放(停止)先前為特定指標事件設定的指標捕獲

setPointerCapture()

將特定元素指定為未來指標事件的捕獲目標

Navigator.maxTouchPoints 屬性用於確定在任何給定時間點支援的最大同時觸控點數。

示例

本節包含使用 Pointer Events 介面基本用法的示例。

註冊事件處理程式

此示例為給定元素的每種事件型別註冊一個處理程式。

html
<div id="target">Touch me…</div>
js
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 rawUpdate_handler(event) {}
function gotCapture_handler(event) {}
function lostCapture_handler(event) {}

const 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.onpointerrawupdate = rawUpdate_handler;
el.ongotpointercapture = gotCapture_handler;
el.onlostpointercapture = lostCapture_handler;

事件屬性

此示例演示如何訪問 Pointer 事件的所有屬性。

html
<div id="target">Touch me…</div>
js
const 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) {
  // Non primary handler
}

function down_handler(ev) {
  // Calculate the touch point's contact area
  const 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 supported`);
  }

  // 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(ev);
}

const el = document.getElementById("target");
// Register pointerdown handler
el.onpointerdown = down_handler;

確定主要指標

在某些情況下,可能存在多個指標(例如,同時具有觸控式螢幕和滑鼠的裝置),或者支援多個接觸點(例如,支援多指觸控的觸控式螢幕)的指標。應用程式可以使用 isPrimary 屬性來識別每種指標型別的活動指標集中的主指標。如果應用程式只想支援主指標,則可以忽略所有非主指標事件。

滑鼠只有一個指標,因此它始終是主指標。對於觸控輸入,如果使用者在沒有其他活動觸控時觸摸了螢幕,則認為該指標是主要的。對於筆和手寫筆輸入,如果使用者在沒有其他活動筆接觸螢幕時最初接觸了螢幕,則認為該指標是主要的。

確定按鈕狀態

某些指標裝置(例如滑鼠和筆)支援多個按鈕,並且按鈕按下可以和絃(即,在指標裝置上的另一個按鈕已經按下時按下附加按鈕)。

為了確定按鈕按下的狀態,Pointer Events 使用 MouseEvent 介面(PointerEvent 繼承自該介面)的 buttonbuttons 屬性。

下表提供了各種裝置按鈕狀態的 buttonbuttons 值。

裝置按鈕狀態 button 按鈕
自上次事件以來按鈕或觸控/筆接觸均未更改 -1
滑鼠移動時未按下按鈕,筆懸停時未按下按鈕移動 0
左鍵滑鼠、觸控接觸、筆接觸 0 1
中鍵滑鼠 1 4
右鍵滑鼠、筆桿按鈕 2 2
X1(後退)滑鼠 3 8
X2(前進)滑鼠 4 16
筆擦除按鈕 5 32

注意: button 屬性表示按鈕狀態的變化。但是,在觸控的情況下,當一個事件發生多個事件時,所有事件都具有相同的值。

捕獲指標

指標捕獲允許將特定 指標事件 的事件重新定向到特定元素,而不是指標位置的正常命中測試。這可用於確保元素即使在指標裝置的接觸點移開元素(例如透過滾動或平移)後仍能繼續接收指標事件。

指標捕獲將導致目標捕獲所有後續指標事件,就像它們發生在捕獲目標上一樣。因此,只要設定了此捕獲,pointeroverpointerenterpointerleavepointerout不會觸發。對於允許直接操作的觸控式螢幕瀏覽器,當 pointerdown 事件觸發時,將在元素上呼叫隱式指標捕獲。可以透過在目標元素上呼叫 element.releasePointerCapture 手動釋放捕獲,或者在 pointeruppointercancel 事件之後隱式釋放。

注意:如果您需要在 DOM 中移動元素,請務必在 DOM 移動之後呼叫 setPointerCapture(),這樣 setPointerCapture() 才不會失去對它的跟蹤。例如,如果您需要使用 Element.append() 將元素移動到其他位置,請務必僅在呼叫 Element.append() 之後才對其呼叫 setPointerCapture()

以下示例顯示在元素上設定了指標捕獲。

html
<div id="target">Touch me…</div>
js
function downHandler(ev) {
  const el = document.getElementById("target");
  // Element 'target' will receive/capture further events
  el.setPointerCapture(ev.pointerId);
}

const el = document.getElementById("target");
el.onpointerdown = downHandler;

以下示例顯示指標捕獲被釋放(當發生 pointercancel 事件時)。當 pointeruppointercancel 事件發生時,瀏覽器會自動執行此操作。

html
<div id="target">Touch me…</div>
js
function downHandler(ev) {
  const el = document.getElementById("target");
  // Element "target" will receive/capture further events
  el.setPointerCapture(ev.pointerId);
}

function cancelHandler(ev) {
  const el = document.getElementById("target");
  // Release the pointer capture
  el.releasePointerCapture(ev.pointerId);
}

const el = document.getElementById("target");
// Register pointerdown and pointercancel handlers
el.onpointerdown = downHandler;
el.onpointercancel = cancelHandler;

touch-action CSS 屬性

touch-action CSS 屬性用於指定瀏覽器是否應將其預設(原生)觸控行為(例如縮放或平移)應用於某個區域。此屬性可以應用於所有元素,除了:非替換的行內元素、表格行、行組、表格列和列組。

auto 值表示瀏覽器可以自由地將其預設觸控行為應用於(指定區域),none 值停用瀏覽器對該區域的預設觸控行為。pan-xpan-y 值表示在該指定區域開始的觸控僅用於水平和垂直滾動。manipulation 值表示瀏覽器可以認為在該元素上開始的觸控僅用於滾動和縮放。

在以下示例中,某些 button 元素的預設觸控行為被停用。

css
button#tiny {
  touch-action: none;
}

在以下示例中,當觸控 target 元素時,它將只在水平方向上平移。

css
#target {
  touch-action: pan-x;
}

與滑鼠事件的相容性

儘管 Pointer Event 介面使應用程式能夠在支援指標的裝置上建立增強的使用者體驗,但現實是,當今絕大多數 Web 內容都設計為僅與滑鼠輸入配合使用。因此,即使瀏覽器支援 Pointer Event,瀏覽器仍然必須處理滑鼠事件,以便假定僅滑鼠輸入的內容無需直接修改即可正常工作。理想情況下,支援 Pointer Event 的應用程式不需要顯式處理滑鼠輸入。但是,由於瀏覽器必須處理滑鼠事件,因此可能需要處理一些相容性問題。本節包含有關 Pointer Event 和滑鼠事件互動以及對應用程式開發人員的影響的資訊。

瀏覽器可以將通用指標輸入對映到滑鼠事件,以實現與基於滑鼠的內容的相容性。這種事件對映稱為相容性滑鼠事件。作者可以透過取消 pointerdown 事件來阻止某些相容性滑鼠事件的產生,但請注意,

  • 滑鼠事件只能在指標按下時阻止。
  • 懸停指標(例如,未按下任何按鈕的滑鼠)無法阻止其滑鼠事件。
  • mouseovermouseoutmouseentermouseleave 事件永遠不會被阻止(即使指標已按下)。

最佳實踐

以下是使用 Pointer Event 時需要考慮的一些最佳實踐

  • 最小化事件處理程式中執行的工作量。
  • 將事件處理程式新增到特定的目標元素(而不是整個文件或文件樹中更高級別的節點)。
  • 目標元素(節點)應足夠大以容納最大的接觸表面積(通常是手指觸控)。如果目標區域太小,觸控它可能會導致為相鄰元素觸發其他事件。

規範

規範
指標事件

瀏覽器相容性

作為 Pointer Events 規範的一部分,已經為 CSS touch-action 屬性定義了一些附加值,但目前這些值的實現支援有限。

另見