@floating-ui/react 是一个专为 React 设计的库,用于创建浮动元素(如 tooltip、popover、dropdown 等)的位置定位和智能摆放。适配 React 的 API 和 Hook,如 useFloating()。
浮动元素常见问题:
@floating-ui/react 会根据目标元素的位置、视口情况自动计算最优位置,并返回一系列用于定位的参数和 style。
npm install @floating-ui/react
下面是一个最简单的 tooltip 示例:
import React, { useState } from 'react';
import { useFloating, offset, flip, shift, autoUpdate } from '@floating-ui/react';
export default function Tooltip() {
const [open, setOpen] = useState(false);
const {
x,
y,
reference,
floating,
strategy,
update,
refs,
} = useFloating({
placement: 'top',
middleware: [offset(8), flip(), shift()],
whileElementsMounted: autoUpdate,
});
return (
<div>
<button
ref={reference}
onMouseEnter={() => setOpen(true)}
onMouseLeave={() => setOpen(false)}
>
Hover me
</button>
{open && (
<div
ref={floating}
style={{
position: strategy,
top: y ?? 0,
left: x ?? 0,
backgroundColor: 'black',
color: 'white',
padding: '6px 12px',
borderRadius: '4px',
zIndex: 9999,
}}
>
Tooltip content
</div>
)}
</div>
);
}
可以,你只需要在浮动层(弹出框)中也监听 onMouseEnter / onMouseLeave,让它和按钮共享控制逻辑,就能避免移动过去时关闭。
import React, { useState } from 'react';
import { useFloating, offset, flip, shift, autoUpdate } from '@floating-ui/react';
export default function Tooltip() {
const [open, setOpen] = useState(false);
const [isHovering, setIsHovering] = useState(false);
const {
x,
y,
reference,
floating,
strategy,
} = useFloating({
placement: 'top',
middleware: [offset(8), flip(), shift()],
whileElementsMounted: autoUpdate,
});
const handleMouseEnter = () => {
setOpen(true);
setIsHovering(true);
};
const handleMouseLeave = () => {
setIsHovering(false);
// 延迟关闭,避免快速移动时闪烁
setTimeout(() => {
if (!isHovering) setOpen(false);
}, 100);
};
return (
<div>
<button
ref={reference}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
Hover me
</button>
{open && (
<div
ref={floating}
style={{
position: strategy,
top: y ?? 0,
left: x ?? 0,
backgroundColor: 'black',
color: 'white',
padding: '6px 12px',
borderRadius: '4px',
zIndex: 9999,
}}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
Tooltip content
</div>
)}
</div>
);
}
setOpen(true)setOpen(false)offset(px):浮动元素距离参考元素的偏移量。flip():如果原来的位置空间不够,则自动翻转方向。shift():防止浮动元素溢出视口。autoUpdate():自动监听滚动或窗口大小变化并重新计算位置。