useElementByPoint
useElementByPoint 是一個用於獲取指定坐標下的元素的 Hook。
useElementByPoint 封裝了 document.elementFromPoint()(或多元素模式下的 elementsFromPoint()),用於響應式查詢給定 x/y 座標處的 DOM 元素。它支援按間隔或透過 requestAnimationFrame 進行輪詢,並回傳一個可暫停的物件,包含匹配的元素、isSupported 旗標以及 pause/resume 控制項。
使用場景
- 建構元素檢查工具或視覺偵錯器,用於高亮懸停的元素
- 實作需要在特定座標偵測放置目標的自訂拖放邏輯
- 建立識別游標下 UI 元素的互動式教學或導覽覆蓋層
注意事項
- SSR 安全:在伺服器端渲染時回傳
isSupported: false和null元素。伺服器上不會存取document。 - 效能:使用
interval選項控制輪詢頻率。requestAnimationFrame提供最流暢的更新,但 CPU 使用率較高。 - 相關 hooks:搭配
useMouse追蹤游標位置,以及useElementBounding獲取偵測到的元素尺寸。
Usage
Live Editor
function Demo() { const { clientX: x, clientY: y } = useMouse(); const { element, pause, resume } = useElementByPoint({ x, y }); const bounding = useElementBounding(element); useEventListener("scroll", bounding.update, null, { capture: true }); const boxStyles = (() => { if (element) { return { display: "block", width: `${bounding.width}px`, height: `${bounding.height}px`, left: `${bounding.left}px`, top: `${bounding.top}px`, backgroundColor: "#3eaf7c44", transition: "all 0.05s linear", position: "fixed", pointerEvents: "none", zIndex: 9999, border: "1px solid var(--vp-c-brand)", }; } return { display: "none", }; })(); const pointStyles = (() => ({ transform: `translate(calc(${x}px - 50%), calc(${y}px - 50%))`, position: "fixed", top: 0, left: 0, pointerEvents: "none", width: "8px", height: "8px", borderRadius: "50%", backgroundColor: "#4ade80", boxShadow: "0 0 2px rgba(0,0,0,0.3)", zIndex: 999, }))(); return ( <> <div style={boxStyles} /> <div style={pointStyles} /> <div style={{ display: "flex", alignItems: "center" }}> <span style={{ marginRight: "16px" }}>X: {x}</span> </div> <div style={{ display: "flex", alignItems: "center" }}> <span style={{ marginRight: "16px" }}>Y: {y}</span> </div> <div> <button onClick={pause}>暫停</button> <button onClick={resume}>恢復</button> </div> </> ); } render(<Demo />);
Result
API
UseElementByPoint
Returns
UseElementByPointReturn<M>
Arguments
| 參數名 | 描述 | 類型 | 預設值 |
|---|---|---|---|
| options | 配置项 | UseElementByPointOptions<M> (必填) | - |
UseElementByPointOptions
| 參數名 | 描述 | 類型 | 預設值 |
|---|---|---|---|
| x | 点的 x 坐标 | number | (() => number) (必填) | - |
| y | 点的 y 坐标 | number | (() => number) (必填) | - |
| document | 要查询的文档 | Document | null | - |
| multiple | 是否查询多个元素 | M | - |
| interval | 查询元素的间隔 | number | 'requestAnimationFrame' | - |
| immediate | 是否立即查询元素 | boolean | - |
UseElementByPointReturn
| 參數名 | 描述 | 類型 | 預設值 |
|---|---|---|---|
| isSupported | 功能是否支持 | boolean (必填) | - |
| element | 查询到的元素 | M extends true ? Element[] : Element | null (必填) | - |
| isActive | 一个 ref,表示一个 pausable 实例是否处于激活状态 | boolean (必填) | - |
| pause | 暂时暂停效果的执行 | Fn (必填) | - |
| resume | 恢复效果 | Fn (必填) | - |
Fn
export type Fn = (this: any, ...args: any[]) => any;