拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Radix Vue Tooltip Cursor 实战:实现一个跟随鼠标光标移动的 Tooltip

Radix Vue Tooltip Cursor 实战实现一个跟随鼠标光标移动的 Tooltip【免费下载链接】radix-vueAn open-source UI component library for building high-quality, accessible design systems and web apps for Vue. Previously Radix Vue项目地址: https://gitcode.com/GitHub_Trending/ra/radix-vue导读本篇文章围绕 Radix Vue现 reka-ui曾用名 Radix Vue仓库中官方示例Tooltip Cursor展开讲解如何基于Tooltip组件实现Tooltip 跟随鼠标光标移动的交互效果。读者将掌握虚拟锚点virtual reference的用法、update-position-strategyalways实时定位的原理以及如何用受控open状态把指针坐标喂给 Tooltip 定位系统。示例源码位于 docs/components/examples/TooltipCursor/index.vue配套演示页为 docs/content/examples/tooltip-cursor.md。功能概览什么是 Tooltip Cursor官方文档对 Tooltip Cursor 的描述只有一句话却点明了核心诉求Render a Tooltip that follows the cursor when hovering over the target element.即当鼠标悬停在目标元素上时渲染一个跟随光标移动的 Tooltip。这与常规 Tooltip 有本质区别——普通 Tooltip 锚定在触发元素上位置相对固定而 Tooltip Cursor 中内容层会像磁铁一样实时吸附在光标所在坐标上常用于标注、辅助说明、实时坐标提示等场景。在 docs/content/examples/tooltip-cursor.md 中该示例通过ComponentPreview typeexample nameTooltipCursor /挂载到演示页其真实实现位于 docs/components/examples/TooltipCursor/index.vue。完整实现拆解跟随光标的 Tooltip先看示例的完整模板已省略样式类script setup langts import { TooltipArrow, TooltipContent, TooltipPortal, TooltipProvider, TooltipRoot, TooltipTrigger } from reka-ui import { computed, ref } from vue const open ref(false) const anchor ref({ x: 0, y: 0, }) const position computed(() ({ getBoundingClientRect: () ({ width: 0, height: 0, left: anchor.value.x, right: anchor.value.x, top: anchor.value.y, bottom: anchor.value.y, ...anchor.value, } as DOMRect), })) /script template TooltipProvider :delay-duration0 div class...container 样式... pointerenteropen true pointerleaveopen false pointermove(ev) { anchor.x ev.clientX anchor.y ev.clientY } Container /div TooltipRoot :openopen TooltipTrigger :referenceposition / TooltipPortal TooltipContent sidetop :side-offset12 class...content 样式... update-position-strategyalways Following TooltipArrow class... / /TooltipContent /TooltipPortal /TooltipRoot /TooltipProvider /template这段代码把跟随光标拆解成了三个可复用的技术要点下面逐一深入。1. 用指针事件驱动受控 open 状态示例没有依赖 Tooltip 自带的 hover 触发逻辑而是完全受控地接管开关容器div上监听pointerenter进入时把open置为true监听pointerleave离开时置回falseTooltipRoot通过:openopen接收受控状态。这样做的目的很明确光标跟随需要 Tooltip 在鼠标移入的瞬间就显示而不是等TooltipTrigger内部默认的延时逻辑。配合外层TooltipProvider的:delay-duration0把悬停到打开的延迟从默认值 700ms见 TooltipProvider.vue 中delayDuration的defaultValue 700降为 0实现即时弹出。值得注意的是示例中的TooltipTrigger是一个空标签没有内容它在这里的唯一职责是向定位系统注册锚点而真正的触发面是外层那个宽高可点的容器div。2. 虚拟锚点用一个假元素做定位基准这是整个示例最精髓的部分。常规用法中TooltipTrigger会把自己渲染出的 DOM 元素作为锚点anchorTooltip 内容层相对锚点定位。而这里定义了一个 computed 对象positionconst position computed(() ({ getBoundingClientRect: () ({ width: 0, height: 0, left: anchor.value.x, right: anchor.value.x, top: anchor.value.y, bottom: anchor.value.y, ...anchor.value, } as DOMRect), }))position是一个模拟 DOMRect 的虚拟元素它不真实存在于页面但实现了getBoundingClientRect()方法返回一个宽高为 0、四边坐标全部等于当前光标坐标的矩形。由于width和height都是 0这个锚点就是一个位于光标处的点Tooltip 便会围绕这个点进行定位。然后通过TooltipTrigger的referenceprop 把这个虚拟元素交给定位系统TooltipTrigger :referenceposition /reference属性继承自PopperAnchorProps在 PopperAnchor.vue 中的定义是/** * The reference (or anchor) element that is being referred to for positioning. * * If not provided will use the current component as anchor. */ reference?: ReferenceElement当不传reference时组件自身 DOM 会作为锚点传了之后就会用传入的ReferenceElement即这里的虚拟元素替代。在 PopperContent.vue 中也可以看到同一逻辑// If provided custom reference, it will overwrite the default anchor element const reference computed(() props.reference ?? rootContext.anchor.value)Floating UI本项目 Popper 层依赖的定位库只要求 reference 具备getBoundingClientRect因此这种虚拟锚点是官方推荐的浮层跟随技术Tooltip、Popover、Select 等所有基于 Popper 的组件都适用。3. 实时跟随update-position-strategyalways有了虚拟锚点还必须让 Tooltip 内容层持续跟随光标刷新坐标否则位置只在初次打开时计算一次。示例在TooltipContent上开启了TooltipContent ... update-position-strategyalways这个属性在 PopperContent.vue 中定义默认值是optimized可取值optimized | always。它直接作用于定位库autoUpdate的配置const cleanup autoUpdate(...args, { layoutShift: !props.disableUpdateOnLayoutShift, animationFrame: props.updatePositionStrategy always, })optimized默认只在特定时机滚动、窗口尺寸变化、元素位移等触发重新定位性能开销小但对跟随光标这种高频场景不够及时always开启animationFrame让定位计算跟随浏览器的每一帧刷新requestAnimationFrame 驱动从而把 Tooltip 平滑地粘在光标上。这正是光标跟随效果能成立的性能开关每次pointermove更新anchor.x / anchor.yposition计算属性随之变化下一帧定位系统就会按新坐标重新摆放 Tooltip。4. 细节side、sideOffset 与箭头示例中TooltipContent还设置了sidetop内容层优先显示在锚点光标上方:side-offset12与锚点保持 12px 间距避免内容直接盖住光标遮挡用户视线内部放了一个TooltipArrow并配合样式使其跟随内容层移动视觉上形成从光标处伸出的小气泡。这些属性同样来自 Popper 层side、sideOffset的默认值在 PopperContent.vue 中分别为bottom和0示例将其覆盖为top与12。底层支撑TooltipTrigger 的指针处理逻辑为什么这里要自己接管pointerenter/pointermove而不是复用TooltipTrigger内置的悬停逻辑看 TooltipTrigger.vue 的实现就明白了。其内置的pointermove处理器只负责触发打开并不持续上报坐标function handlePointerMove(event: PointerEvent) { if (event.pointerType touch) return if ( !hasPointerMoveOpened.value !providerContext.isPointerInTransitRef.value ) { rootContext.onTriggerEnter() hasPointerMoveOpened.value true } }从中可以推断出三点设计事实触屏设备会被过滤event.pointerType touch时直接返回因为手指没有悬停语义光标跟随只对鼠标/触控笔有意义只负责开不负责定位内置逻辑调用onTriggerEnter()打开 Tooltip而坐标追踪需要应用层自己维护——这正是示例用pointermove更新anchor.x/y的原因去抖与防抖由 Provider 管理isPointerInTransitRef由 TooltipProvider.vue 提供配合skipDelayDuration默认 300ms控制指针从一个触发器移到另一个触发器时的延迟重置示例将delay-duration置 0 后这些机制依然生效。无障碍与实用注意点作为基于 Radix Vue 原语组件组合出来的示例光标跟随 Tooltip 依然保留了 Tooltip 原语的无障碍基础能力内容层通过aria-describedby与触发器关联见 TooltipTrigger.vue 中aria-describedby的绑定键盘焦点也能打开 Tooltip。但在实际项目中接入该模式时建议注意以下几点性能权衡update-position-strategyalways意味着每帧都可能触发定位计算元素较多或页面复杂时开销可观可以推断若只要求位置近似跟随将策略改回默认optimized并用节流后的坐标更新是更经济的方案。内容可读性光标跟随的 Tooltip 内容应短小精悍且side-offset不宜过小避免内容覆盖光标造成阅读干扰示例取 12px 即为平衡。受控状态清理示例把open绑定在容器元素上务必保证pointerleave分支存在否则 Tooltip 可能在光标离开后残留。复用边界本例用的是TooltipTrigger 虚拟reference的组合对于更轻量的坐标气泡也可以考虑直接以任意容器配合 Popper 原语自行组装但会失去 Tooltip 原语自带的延时、键盘与无障碍语义。小结Tooltip Cursor 是 Radix Vue 官方示例中展示虚拟锚点 实时定位组合拳的典型用例。通过 docs/components/examples/TooltipCursor/index.vue 我们可以提炼出三条可迁移的技术结论用getBoundingClientRect构造宽高为 0 的虚拟元素即可让任何基于 Popper 的浮层锚定到任意坐标点TooltipTrigger/TooltipContent的reference与update-position-strategy属性前者定义于 PopperAnchor.vue后者实现于 PopperContent.vue是光标跟随得以实现的两个关键开关受控openpointermove事件上报坐标是把交互主动权握在自己手里的标准做法。这套模式不仅适用于 Tooltip也同样可以平移到 Popover、Select 等其它浮层组件是构建交互式标注、实时提示类 UI 的实用技能。【免费下载链接】radix-vueAn open-source UI component library for building high-quality, accessible design systems and web apps for Vue. Previously Radix Vue项目地址: https://gitcode.com/GitHub_Trending/ra/radix-vue创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门