Pointer Capture 讓滑鼠離開元件仍能收事件

拖曳/繪製類互動的標準做法:pointerdown 時呼叫 setPointerCapture(pointerId),這之後不管游標移到哪、即使離開元件甚至離開瀏覽器視窗,所有 pointermovepointerup 都會被導回該元件。

做法

const onPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {
  containerRef.current?.setPointerCapture(e.pointerId)
  // 開始拖曳/繪製...
}
 
const onPointerUp = (e: React.PointerEvent<HTMLDivElement>) => {
  if (containerRef.current?.hasPointerCapture(e.pointerId)) {
    containerRef.current.releasePointerCapture(e.pointerId)
  }
  // 結束...
}

注意要綁 onPointerCancel 也指向同一個 handler,避免系統中斷拖曳時狀態洗不掉。

沒有 Pointer Capture 會發生什麼

使用者按下開始拖、滑出元件再放開 → pointerup 落在外面、你的元件收不到 → 拖曳狀態永遠不會清乾淨 → 之後游標飄回來自動繼續拖(鬼影 bug)。

過去的 workaround 是「mousedownwindow.addEventListener('mousemove'/'mouseup'),結束時記得 remove」,繁瑣又容易漏 cleanup。Pointer Capture 從根本解決,DOM API 內建。

適用場景

  • 畫布拖移、繪製、選取框
  • Slider、Resize handle、Splitter
  • 自製 drag-and-drop
  • 任何「按下開始、放開結束」的互動

Pointer 比 Mouse 多了什麼

  • 同時處理滑鼠 + 觸控 + 筆,一套 API 搞定
  • pointerId 可以區分多指觸控
  • 內建 setPointerCapture,不必再 hack window 事件

幾乎沒有理由再用 mousedown/mousemove/mouseup 三件套。

相關