HUD 用 data 屬性加 closest 阻擋畫布事件
畫布上疊 UI(工具列、屬性面板、HUD)時,在 UI 根元素加 data-hud 標記,畫布的事件 handler 用 e.target.closest('[data-hud]') 判斷是否落在 UI 上、是的話直接 return。
做法
// 畫布 handler
const onPointerDown = (e) => {
if ((e.target as HTMLElement).closest('[data-hud]')) return // 點到 UI 就略過
// 正常畫布邏輯...
}
// UI 元件
<div className="toolbar" data-hud onPointerDown={(e) => e.stopPropagation()}>
...
</div>為什麼比 stopPropagation 更好
只用 stopPropagation:
- 必須在「每個」UI 元素都記得加 — 漏掉一個就破功
- 第三方元件無法控制(例如 Headless UI、Radix 的內部結構)
- 父層其他 listener(如 analytics)也會被連帶擋掉
data-hud + closest:
- 只在 UI 根元素標記一次,所有後代自動受惠
- 判斷邏輯集中在畫布 handler 一處,易維護
- 想擴充新的 HUD 元件只要加
data-hud屬性
兩者搭配最穩:UI 根加 data-hud 防 capture 階段、UI 根再加 stopPropagation 防 bubble 階段。
為什麼用 data-* 而非 className
data-hud是宣告式語意(「我是 HUD」),不是樣式- CSS selector
[data-hud]跟closest都直接支援 - 改 className 不會誤傷判斷邏輯(CSS rename 不影響事件流)
適用場景
- 無限畫布上的工具列、屬性面板、HUD
- 地圖元件上疊控制按鈕
- 任何「下層元素有全域事件 handler,上層需要正常互動」的情境