Skip to content

React

一个 React 工具包,用于定位浮动元素并可选择为它们创建交互。

¥A React toolkit to position floating elements and optionally create interactions for them.

npm install @floating-ui/react

如果你只需要定位而不需要交互,请使用以下较小的打包包大小:

¥If you only need positioning without interactions, use the following for a smaller bundle size:

npm install @floating-ui/react-dom

选择你安装的软件包以获得更好的文档:

¥Choose the package you installed for better docs:

该包的目标是提供基元(所有类型的浮动元素共有的功能)来创建工具提示、弹出窗口、下拉菜单、悬停卡、模式对话框、选择菜单、组合框等组件。

¥The goal of this package is to provide primitives — features common to all types of floating elements — to create components for tooltips, popovers, dropdown menus, hover cards, modal dialogs, select menus, comboboxes, and more.

它不提供任何预构建的组件,而是为你提供更轻松地创建它们的工具。如果你想要大量控制,但确实需要更多工作才能开始,那么这是理想的选择。React 示例 中的完整指南包含一些可复制粘贴的示例,可帮助你更快地入门。

¥Instead of providing any pre-built components, it gives you the tools to create them more easily. This is ideal if you want lots of control, but does require more work to get started. The full guides in React Examples contain some copy-pasteable examples to get you started more quickly.

用法

¥Usage

Floating UI 的用法可以分为两个不同的部分:

¥Floating UI’s usage can be broken down into two disparate parts:

  • 定位(适用于 @floating-ui/react@floating-ui/react-dom)。

    ¥Positioning (available for both @floating-ui/react and @floating-ui/react-dom).

  • 互动(仅适用于 @floating-ui/react)。

    ¥Interactions (available for only @floating-ui/react).

定位

¥Positioning

useFloating() 是每个包的主要 Hook。

¥useFloating() is the main Hook of each package.

最基本的是,Hook 返回一个 refs 对象和一个 floatingStyles 对象:

¥At its most basic, the Hook returns a refs object and a floatingStyles object:

function App() {
  const {refs, floatingStyles} = useFloating();
  return (
    <>
      <button ref={refs.setReference}>Button</button>
      <div ref={refs.setFloating} style={floatingStyles}>
        Tooltip
      </div>
    </>
  );
}

默认情况下,这会将浮动 Tooltip 元素定位在 Button 元素的底部中心。

¥This will position the floating Tooltip element at the bottom center of the Button element by default.

  • refs.setReference 设置用于定位的参考(或锚点)元素。

    ¥refs.setReference sets the reference (or anchor) element that is being referred to for positioning.

  • refs.setFloating 设置相对于参考元素定位的浮动元素。

    ¥refs.setFloating sets the floating element that is being positioned relative to the reference element.

  • floatingStyles 是应用于浮动元素的 style 属性的定位样式对象。

    ¥floatingStyles is an object of positioning styles to apply to the floating element’s style prop.

引用是回调引用(函数),使它们具有反应性 - 这确保通过更新位置正确处理引用或浮动元素的更改(例如条件渲染)。

¥The refs are callback refs (functions) to make them reactive — this ensures changes to the reference or floating elements, such as with conditional rendering, are handled correctly by updating the position.

锚定

¥Anchoring

为了确保浮动元素保持锚定到参考元素,例如在滚动或调整大小时,请将 autoUpdate 传递给 whileElementsMounted 选项:

¥To ensure the floating element remains anchored to the reference element, such as when scrolling or resizing, pass autoUpdate to the whileElementsMounted option:

const {refs, floatingStyles} = useFloating({
  whileElementsMounted: autoUpdate,
});

API 文档

¥API docs

请访问完整的 useFloating API 文档,了解有关自定义浮动元素定位的详细信息。

¥Visit the full useFloating API docs for detailed information about customizing the positioning of floating elements.

测试

¥Testing

测试组件时,请确保在浮动元素渲染后立即刷新微任务。这将避免 act 警告。

¥When testing your components, ensure you flush microtasks immediately after the floating element renders. This will avoid the act warning.

import {act} from '@testing-library/react';
 
test('something', async () => {
  render(<Tooltip open />);
  await act(async () => {}); // Flush microtasks.
  // Position state is ready by this line.
});

你可能会经常使用它,因此你可以创建一个自定义函数:

¥You may use this a lot, so you can create a custom function:

const waitForPosition = () => act(async () => {});
 
test('something', async () => {
  render(<Tooltip open />);
  await waitForPosition();
  expect(screen.queryByRole('tooltip')).toBeInTheDocument();
});

收缩引用类型

¥Narrow reference type

由于 虚拟元素,你在对 ref 执行 DOM 操作时可能需要缩小类型:

¥Due to virtual elements, you may need to narrow the type when performing DOM operations on the ref:

互动

¥Interactions

要添加交互,例如在将鼠标悬停在参考元素上时仅显示浮动元素的能力,Hook 必须首先接受以下两个选项:

¥To add interactions, such as the ability to only show a floating element while hovering over its reference element, the Hook must first accept the following two options:

  • openboolean 表示当前是否渲染浮动元素。

    ¥open — a boolean that represents whether the floating element is currently rendered.

  • onOpenChange — 当打开布尔状态发生变化时调用 event callback

    ¥onOpenChange — an event callback invoked when the open boolean state should change.

import {useFloating} from '@floating-ui/react';
 
function App() {
  const [isOpen, setIsOpen] = useState(false);
 
  const {refs, floatingStyles} = useFloating({
    open: isOpen,
    onOpenChange: setIsOpen,
  });
 
  return (
    <>
      <button ref={refs.setReference}>Button</button>
      {isOpen && (
        <div ref={refs.setFloating} style={floatingStyles}>
          Tooltip
        </div>
      )}
    </>
  );
}

请注意,浮动组件并不总是需要 “锚定位”,因此可以忽略 floatingStyles

¥Note that floating components do not always require “anchor positioning”, so floatingStyles can be ignored.

钩子

¥Hooks

交互钩子允许改变打开状态以及其他功能。每个交互 Hook 接受从 useFloating() 返回的 context 对象作为其第一个参数:

¥Interaction Hooks allow the open state to change, among other functionality. Each interaction Hook accepts the context object which gets returned from useFloating() as their first argument:

import {
  useFloating,
  useInteractions,
  useHover,
  useFocus,
} from '@floating-ui/react';
 
// Inside your component
const {refs, context} = useFloating({
  open: isOpen,
  onOpenChange: setIsOpen,
});
 
const hover = useHover(context);
const focus = useFocus(context);
 
const {getReferenceProps, getFloatingProps} = useInteractions([
  hover,
  focus,
]);

useHover()useFocus() Hooks 设置 Effects 并返回事件处理程序 props 来更改打开状态,后者由 useInteractions() 合并进行渲染。

¥The useHover() and useFocus() Hooks set up Effects and return event handler props to change the open state, the latter of which get merged by useInteractions() for rendering.

该 API 使每个 Hook 都能够完全进行树摇动和选择加入。左侧的导航栏详细解释了它们。

¥This API enables each of the Hooks to be fully tree-shakeable and opt-in. The navigation bar on the left explains them in detail.

属性获取器

¥Prop getters

prop getter 用于将从交互 Hooks 返回的事件处理程序以及其他功能添加到引用和浮动元素。当被调用时,它们返回一个像 onFocus 这样的 props 对象。

¥The prop getters are used to add event handlers returned from the interaction Hooks, among other functionality, to the reference and floating elements. When called, they return an object of props like onFocus.

<>
  <button ref={refs.setReference} {...getReferenceProps()}>
    My button
  </button>
  <div
    ref={refs.setFloating}
    style={floatingStyles}
    {...getFloatingProps()}
  >
    My tooltip
  </div>
</>

打开事件回调

¥Open event callback

使用可选定义的 event objectreason string 作为第二个和第三个参数来调用 onOpenChange 事件回调:

¥The onOpenChange event callback is invoked with an optionally-defined event object and reason string as the second and third parameter:

useFloating({
  onOpenChange(isOpen, event, reason) {
    setIsOpen(isOpen);
    event && console.log(event);
    reason && console.log(reason);
  },
});

请注意,如果你通过 setIsOpen() setter 手动更改打开状态,则不会调用 onOpenChange。无论如何,在这种情况下你都可以自己导出事件。

¥Note that onOpenChange is not called if you manually changed the open state via the setIsOpen() setter. You can derive the event yourself in this case anyway.

在保留事件的同时更改定位参考

¥Changing the positioning reference while retaining events

  • 默认情况下,refs.setReference 元素既是事件又是位置引用。

    ¥refs.setReference element is both the events and position reference by default.

  • refs.setPositionReference 允许你将位置分离到另一个元素(真实或虚拟)。

    ¥refs.setPositionReference allows you to separate the position to another element (either real or virtual).

const {refs} = useFloating();
 
return (
  <>
    <button ref={refs.setReference} {...getReferenceProps()}>
      Event reference
    </button>
    <button ref={refs.setPositionReference}>
      Position reference
    </button>
  </>
);

在 CodeSandbox 上查看

¥View on CodeSandbox

单个参考元素上的多个浮动元素

¥Multiple floating elements on a single reference element

import {useMergeRefs} from '@floating-ui/react';

Refs 可以与 useMergeRefs hook 合并,props 可以通过调用另一个 getter 中的一个来合并:

¥Refs can be merged with the useMergeRefs hook, and props can be merged by calling one of the getters inside of the other:

const {refs: tooltipRefs} = useFloating();
const {refs: menuRefs} = useFloating();
 
const {getReferenceProps: getTooltipReferenceProps} =
  useInteractions([]);
const {getReferenceProps: getMenuReferenceProps} =
  useInteractions([]);
 
const ref = useMergeRefs([
  tooltipRefs.setReference,
  menuRefs.setReference,
]);
const props = getTooltipReferenceProps(getMenuReferenceProps());
 
return (
  <button ref={ref} {...props}>
    Common reference
  </button>
);

在 CodeSandbox 上查看

¥View on CodeSandbox

禁用元素

¥Disabled elements

禁用的元素不会触发事件,因此附加到禁用按钮的工具提示不会显示。避免使用 disabled 属性,并让按钮在视觉上被禁用。这可确保你不需要任何封装标签,并使所有用户都可以访问工具提示。

¥Disabled elements don’t fire events, so tooltips attached to disabled buttons don’t show. Avoid using the disabled prop, and make the button visually disabled instead. This ensures you won’t need any wrapper tags and makes the tooltip accessible to all users.

在 CodeSandbox 上查看

¥View on CodeSandbox