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;