Skip to content

迁移

¥Migration

了解如何从 Popper v2 迁移到 Floating UI。

¥Learn how to migrate from Popper v2 to Floating UI.

品牌重塑:该库被重新命名,因为它提供了更多的包和功能,例如提供交互的新 React 包,而 Popper 只提供定位。

¥Rebranding: The library was rebranded as it offers more packages and functionality, like the new React package that provides interactions, while Popper only ever offered positioning.

新的 API:新 API 的目标是使 Floating UI 变得更底层别,使其更像 CSS,你可以在其中逐步添加属性以实现所需的定位行为,而无需预先配置任何内容。

¥New API: The goal of the new API was to make Floating UI lower-level and act more like CSS in which you progressively add properties to achieve the desired positioning behavior, without pre-configuring anything.

此外,我们希望使配置更加符合人机工程学,使库更小并且完全可摇树(因此新功能如果未使用,不会使打包包膨胀),并且还希望按照要求支持 React Native/Canvas,即 现在支持。

¥In addition, we wanted to make the configuration more ergonomic, the library smaller and fully tree-shakeable (so new features don’t bloat bundles if unused), and also wanted to support React Native/Canvas as they had been requested, which is now supported.

不同但熟悉:Floating UI 是 Popper 2 的分支,并且有很多相似之处。虽然主要的外部定位功能发生了变化,但 API 的许多其他部分是相似的。

¥Different, but familiar: Floating UI forked Popper 2 and shares a lot of similarities. While the main external positioning function changed, many other parts of the API are similar.

相似之处包括:

¥Similarities include:

  • 定位函数的参数顺序和类型实际上是相同的。

    ¥The order of arguments and types of the positioning function are practically identical.

  • placementstrategy 相同,作为第三个参数选项对象传递。

    ¥placement and strategy are the same, passed as a third argument options object.

  • Floating UI 中的 middleware 在概念上类似于 Popper 2 中的 modifiers

    ¥middleware in Floating UI is conceptually similar to modifiers from Popper 2.

  • 传递给中间件的选项与 Popper 2 具有非常相似的配置,并且 detectOverflow 和虚拟元素等 API 几乎相同。

    ¥Options passed to middleware have very similar configuration as Popper 2, and APIs like detectOverflow and virtual elements are almost identical.

改变依赖

¥Change dependencies

首先,卸载 @popperjs/core 并安装 @floating-ui/dom

¥First thing’s first, uninstall @popperjs/core and install @floating-ui/dom.

npm uninstall @popperjs/core
npm install @floating-ui/dom

定位功能变更

¥Positioning function change

默认情况下,波普尔会为你应用样式并添加修饰符。另一方面,Floating UI 完全是简单的 - 你无需预先配置任何内容即可添加所需内容。

¥Popper applied styles and added modifiers for you by default. Floating UI on the other hand is completely bare bones — you add what you need with nothing pre-configured.

在 Popper 中,你像这样调用 createPopper(),它会自动将 popper 元素放置在底部。

¥In Popper, you called createPopper() like so and it would place the popper element at the bottom for you automatically.

import {createPopper} from '@popperjs/core';
 
createPopper(reference, popper);

Floating UI 不会为你应用样式或添加修饰符(现在更通用地称为中间件)。相反,它是纯粹的,只返回你可以随意使用的数据。

¥Floating UI does not apply styles or add modifiers (now more generically called middleware) for you. Instead it’s pure and only returns data that you can use as you please.

在 CSS 中的浮动元素上设置 初始样式

¥Set up the initial styles on the floating element in your CSS:

.floating {
  width: max-content;
  position: absolute;
  top: 0;
  left: 0;
}

然后,使用函数解析的定位数据应用坐标:

¥Then, apply the coordinates using the positioning data resolved by the function:

import {computePosition} from '@floating-ui/dom';
 
computePosition(referenceEl, floatingEl).then(({x, y}) => {
  Object.assign(floatingEl.style, {
    left: `${x}px`,
    top: `${y}px`,
  });
});

了解有关 这里是 computePosition 的更多信息。

¥Read more about computePosition here.

自动更新位置

¥Updating the position automatically

computePosition() 不是有状态的,它只定位你的元素一次。

¥computePosition() is not stateful, it only positions your element once.

Popper 自动添加监听器来更新滚动位置和调整大小。在 Floating UI 中,你自己添加它,并且更明确地表明它需要清理:

¥Popper added listeners automatically to update the position on scroll and resize. In Floating UI, you add this yourself, and it’s much more explicit that it needs to be cleaned up:

import {computePosition, autoUpdate} from '@floating-ui/dom';
 
// When the floating element is open on the screen
const cleanup = autoUpdate(referenceEl, floatingEl, () => {
  computePosition(referenceEl, floatingEl).then(({x, y}) => {
    Object.assign(floatingEl.style, {
      left: `${x}px`,
      top: `${y}px`,
    });
  });
});
 
// When the floating element is removed from the screen
cleanup();

与 Popper 不同,Floating UI 还默认添加 ResizeObserver 监听器,处理额外的更新边缘情况。

¥Floating UI also adds ResizeObserver listeners by default, unlike Popper, handling an additional update edge case.

了解有关 这里是 autoUpdate 的更多信息。

¥Read more about autoUpdate here.

配置中间件

¥Configure middleware

Floating UI 遵循你传入的 placement,默认情况下不会修改它:

¥Floating UI honors the placement you passed in and does not modify it by default:

import {computePosition} from '@floating-ui/dom';
 
computePosition(referenceEl, floatingEl, {
  placement: 'top',
}).then(({x, y}) => {
  // ...
});

即使浮动元素会溢出屏幕顶部,它仍然会被放置并锚定在那里。

¥Even if the floating element will overflow the top of the screen, it will still be placed and anchored there.

如果你想直接匹配 Popper 的默认行为以防止冲突,请按以下顺序添加 flip()shift()limitShift()

¥If you’d like to directly match Popper’s default behavior to prevent collisions, add in flip(), shift() and limitShift() in the following order:

import {
  computePosition,
  flip,
  shift,
  limitShift,
} from '@floating-ui/dom';
 
computePosition(referenceEl, floatingEl, {
  placement: 'top',
  middleware: [flip(), shift({limiter: limitShift()})],
}).then(({x, y}) => {
  // ...
});

与 Popper 2 不同,数组的顺序很重要,并且不会为你进行调整。中间件 页详细解释了这个概念。本质上,如果将一个中间件放置在另一个中间件之前或之后,定位结果可能会发生变化。这有助于实现完全控制,因为有时你需要根据顺序采取不同的行为。

¥Unlike Popper 2, the order of the array matters and is not adjusted for you. The Middleware page explains the concept in detail. Essentially, if you place one of the middleware before or after another, the positioning result can change. This helps enable full control as sometimes you want different behavior based on the ordering.

Popper 的 preventOverflow 修饰符现在称为 shift。这是因为从技术上讲,Popper 2 “防止溢出” 中的许多修饰符并没有描述它与 shift 不同的实际用途。

¥The preventOverflow modifier from Popper is now called shift. This is because technically many modifiers in Popper 2 “prevented overflow”, which does not describe what it is actually doing unlike shift.

你可能会注意到 API 在函数调用时更加符合人机工程学。

¥You’ll hopefully notice the API is much more ergonomic at the point of the function call.

波普尔 2:

¥Popper 2:

createPopper(reference, popper, {
  modifiers: [
    {
      name: 'offset',
      options: {
        offset: [0, 10],
      },
    },
  ],
});

浮动用户界面:

¥Floating UI:

computePosition(referenceEl, floatingEl, {
  middleware: [offset(10)],
});

传递给中间件选项的许多选项与 Popper 2 相似或相同。要了解他们的选项,你可以阅读左侧边栏上的页面。

¥A lot of the options passed in to middleware options are similar or the same as Popper 2. To learn about their options, you can read their pages on the sidebar on the left.

箭头样式

¥Arrows styling

在 Popper 中,你可以在 Popper 中添加 data-popper-arrow 元素,它会自动被拾取并设置样式。

¥In Popper you could add a data-popper-arrow element inside your popper and it’d automatically be picked up and styled.

由于 Floating UI 是纯粹的,你现在可以自己处理这些样式,并且始终手动传递元素。你可以在 arrow 中间件 页面上阅读更多相关信息。

¥As Floating UI is pure, you now handle these styles yourself, and you always pass an element in manually. You can read more about this on the arrow middleware page.

自动放置现在是一个中间件

¥Auto placement is now a middleware

在 Popper 2 中,这是 flip 的一部分,但现在它是独立的,不再是 placement 的字符串选项。

¥In Popper 2, this was part of flip but now it’s separate and is no longer a string option for placement.

波普尔 2:

¥Popper 2:

import {createPopper} from '@popperjs/core';
 
createPopper(reference, popper, {
  placement: 'auto',
});

浮动用户界面:

¥Floating UI:

import {computePosition, autoPlacement} from '@floating-ui/dom';
 
computePosition(referenceEl, floatingEl, {
  middleware: [autoPlacement()],
});

其他

¥Other

detectOverflow虚拟元素 这样的 API 与 Popper 2 基本相同,只有细微的差别。

¥APIs like detectOverflow and virtual elements are basically the same as Popper 2 with only minor differences.

现在必须在调用 detectOverflow() 之前使用 await 关键字,但接受与 Popper 2 相同的选项,但有细微差别。

¥detectOverflow() must now be called with the await keyword before it but accepts the same options as Popper 2 with minor differences.

结论

¥Conclusion

如果你认为缺少某些内容或感到困惑,你可以在 GitHub 仓库 上打开讨论,我们将尽力改进此页面。

¥If you think something is missing or are confused, you can open a Discussion on the GitHub repo and we’ll try to improve this page.