Skip to content

useTransition

提供将 CSS 过渡应用到浮动元素的能力,包括正确处理 “placement-aware” 过渡。

¥Provides the ability to apply CSS transitions to a floating element, including correct handling of “placement-aware” transitions.

import {
  useTransitionStyles,
  useTransitionStatus,
} from '@floating-ui/react';

你可以使用两种不同的 Hook:

¥There are two different Hooks you can use:

  • useTransitionStylesuseTransitionStatus 的高级封装器,它为你返回计算的样式。这更简单,可以处理大多数用例。

    ¥useTransitionStyles is a high level wrapper around useTransitionStatus that returns computed styles for you. This is simpler and can handle the majority of use cases.

  • useTransitionStatus 是一个底层钩子,它返回一个状态字符串以自行计算样式。

    ¥useTransitionStatus is a low level hook that returns a status string to compute the styles yourself.

useTransitionStyles()

此 Hook 提供了计算的内联样式,你可以将其传播到浮动元素的 style 属性中。

¥This Hook provides computed inline styles that you can spread into the style prop for a floating element.

这个 Hook 是一个独立的 hook,它接受从 useFloating() 返回的 context 对象:

¥This Hook is a standalone hook that accepts the context object returned from useFloating():

function App() {
  const {context} = useFloating();
  const {isMounted, styles} = useTransitionStyles(context);
 
  return (
    isMounted && (
      <div
        style={{
          // Transition styles
          ...styles,
        }}
      >
        Tooltip
      </div>
    )
  );
}
  • isMounted 是一个布尔值,用于确定浮动元素是否安装在屏幕上,从而允许播放卸载动画。这取代了 open 状态变量。

    ¥isMounted is a boolean that determines whether or not the floating element is mounted on the screen, which allows for unmounting animations to play. This replaces the open state variable.

  • styles 是内联过渡样式 (React.CSSProperties) 的对象。

    ¥styles is an object of inline transition styles (React.CSSProperties).

Hook 默认为基本的不透明淡入淡出过渡,持续时间为 250 毫秒。

¥The Hook defaults to a basic opacity fade transition with a duration of 250ms.

useTransitionStyles() 属性

¥useTransitionStyles() Props

interface UseTransitionStylesProps {
  duration?: number | Partial<{open: number; close: number}>;
  initial?: CSSStylesProperty;
  open?: CSSStylesProperty;
  close?: CSSStylesProperty;
  common?: CSSStylesProperty;
}

duration

默认:250

¥default: 250

指定转换的长度(以毫秒为单位)。

¥Specifies the length of the transition in ms.

const {isMounted, styles} = useTransitionStyles(context, {
  // Configure both open and close durations:
  duration: 200,
  // Or, configure open and close durations separately:
  duration: {
    open: 200,
    close: 100,
  },
});

initial

默认:{opacity: 0}

¥default: {opacity: 0}

指定浮动元素的初始样式:

¥Specifies the initial styles of the floating element:

const {isMounted, styles} = useTransitionStyles(context, {
  initial: {
    opacity: 0,
    transform: 'scale(0.8)',
  },
});

这将隐式转换为每个值的空字符串(默认为 opacity: 1transform: scale(1))。

¥This will implicitly transition to empty strings for each value (their defaults of opacity: 1 and transform: scale(1)).

对于位置感知样式,你可以定义一个函数:

¥For placement-aware styles, you can define a function:

const {isMounted, styles} = useTransitionStyles(context, {
  initial: ({side}) => ({
    transform:
      side === 'top' || side === 'bottom'
        ? 'scaleY(0.5)'
        : 'scaleX(0.5)',
  }),
});

该函数采用以下参数:

¥The function takes the following parameters:

interface Params {
  side: Side;
  placement: Placement;
}
  • side 代表物理面 - 对于绝大多数转换,你可能只需要关心该面。

    ¥side represents a physical side — with the vast majority of transitions, you’ll likely only need to be concerned about the side.

  • 如果你还想根据对齐方式更改过渡,则 placement 表示整个放置字符串。

    ¥placement represents the whole placement string in cases where you want to also change the transition based on the alignment.

close

默认:undefined

¥default: undefined

默认情况下,过渡是对称的,但如果你想要非对称过渡,则可以指定 close 样式:

¥By default, transitions are symmetric, but if you want an asymmetric transition, then you can specify close styles:

const {isMounted, styles} = useTransitionStyles(context, {
  close: {
    opacity: 0,
    transform: 'scale(2)',
  },
  // Or, for side-aware styles:
  close: ({side}) => ({
    opacity: 0,
    transform:
      side === 'top' || side === 'bottom'
        ? 'scaleY(2)'
        : 'scaleX(2)',
  }),
});

open

默认:undefined

¥default: undefined

如果希望打开状态过渡为非默认样式,可以指定 open 样式:

¥If you want the open state to transition to a non-default style, open styles can be specified:

const {isMounted, styles} = useTransitionStyles(context, {
  open: {
    transform: 'scale(1.1)',
  },
  // or, for side-aware styles:
  open: ({side}) => ({
    transform:
      side === 'top' || side === 'bottom'
        ? 'scaleY(1.1)'
        : 'scaleX(1.1)',
  }),
});

common

默认:undefined

¥default: undefined

如果样式在所有状态中都是通用的,则可以指定此选项。例如,应该共享变换原点:

¥If a style is common across all states, then this option can be specified. For instance, a transform origin should be shared:

const {isMounted, styles} = useTransitionStyles(context, {
  common: {
    transformOrigin: 'bottom',
  },
  // Or, for side-aware styles:
  common: ({side}) => ({
    transformOrigin: {
      top: 'bottom',
      bottom: 'top',
      left: 'right',
      right: 'left',
    }[side],
  }),
});

尺度变换

¥Scale transforms

当对浮动元素的比例进行动画处理时,浮动元素的 transformOrigin 位于箭头的提示看起来效果最好。arrow 中间件提供了实现此目的的数据。

¥When animating the floating element’s scale, it looks best if the floating element’s transformOrigin is at the tip of the arrow. The arrow middleware provides data to achieve this.

在 CodeSandbox 上查看

¥View on CodeSandbox

useTransitionStatus()

该 Hook 提供了一个 status 字符串,用于确定浮动元素是否处于以下四种状态之一:

¥This Hook provides a status string that determines if the floating element is in one of four states:

type Status = 'unmounted' | 'initial' | 'open' | 'close';
 
// Cycle:
// unmounted -> initial -> open -> close -> unmounted

这个 Hook 是一个独立的 hook,它接受从 useFloating() 返回的 context 对象:

¥This Hook is a standalone hook that accepts the context object returned from useFloating():

function App() {
  const {context, placement} = useFloating();
  const {isMounted, status} = useTransitionStatus(context);
 
  return (
    isMounted && (
      <div id="floating" data-status={status}>
        Tooltip
      </div>
    )
  );
}
  • isMounted 是一个布尔值,用于确定浮动元素是否安装在屏幕上,从而允许播放卸载动画。这取代了 open 状态变量。

    ¥isMounted is a boolean that determines whether or not the floating element is mounted on the screen, which allows for unmounting animations to play. This replaces the open state variable.

  • status 是状态字符串 (Status)。

    ¥status is the status string (Status).

上面,我们将 data-status 属性应用于浮动元素。这可用于定位 CSS 中的转换状态。

¥Above, we apply a data-status attribute to the floating element. This can be used to target the transition status in our CSS.

要定义不透明度淡入淡出 CSS 过渡:

¥To define an opacity fade CSS transition:

#floating {
  transition-property: opacity;
}
#floating[data-status='open'],
#floating[data-status='close'] {
  transition-duration: 250ms;
}
#floating[data-status='initial'],
#floating[data-status='close'] {
  opacity: 0;
}
  • transition-property: opacity 适用于所有状态。这允许转换是可中断的。

    ¥transition-property: opacity is applied to all states. This allows the transition to be interruptible.

状态映射到以下内容:

¥The statuses map to the following:

  • 'unmounted' 表示该元素已从屏幕上卸载。在此状态下不需要应用任何过渡或样式。

    ¥'unmounted' indicates the element is unmounted from the screen. No transitions or styles need to be applied in this state.

  • 'initial' 表示浮动元素插入 DOM 后的初始样式。

    ¥'initial' indicates the initial styles of the floating element as soon as it has been inserted into the DOM.

  • 'open' 表示浮动元素处于打开状态(插入后 1 帧)并开始过渡。

    ¥'open' indicates the floating element is in the open state (1 frame after insertion) and begins transitioning in.

  • 'close' 表示浮动元素处于关闭状态并开始转出。

    ¥'close' indicates the floating element is in the close state and begins transitioning out.

转换持续时间必须与传递给 Hook 的 duration 选项匹配。

¥The transition duration must match the duration option passed to the Hook.

不对称转变

¥Asymmetric transitions

#floating {
  transition-property: opacity, transform;
}
#floating[data-status='initial'] {
  opacity: 0;
  transform: scale(0);
}
#floating[data-status='open'] {
  opacity: 1;
  transform: scale(1);
  transition-duration: 250ms;
}
#floating[data-status='close'] {
  opacity: 0;
  transform: scale(2);
  transition-duration: 250ms;
}

位置感知转换

¥Placement-aware transitions

const {context, placement} = useFloating();
const {isMounted, status} = useTransitionStatus(context);
 
return (
  isMounted && (
    <div
      id="floating"
      data-placement={placement}
      data-status={status}
    >
      Tooltip
    </div>
  )
);
#floating {
  transition-property: opacity, transform;
}
#floating[data-status='open'],
#floating[data-status='close'] {
  transition-duration: 250ms;
}
#floating[data-status='initial'],
#floating[data-status='close'] {
  opacity: 0;
}
#floating[data-status='initial'][data-placement^='top'],
#floating[data-status='close'][data-placement^='top'] {
  transform: translateY(5px);
}
#floating[data-status='initial'][data-placement^='bottom'],
#floating[data-status='close'][data-placement^='bottom'] {
  transform: translateY(-5px);
}
#floating[data-status='initial'][data-placement^='left'],
#floating[data-status='close'][data-placement^='left'] {
  transform: translateX(5px);
}
#floating[data-status='initial'][data-placement^='right'],
#floating[data-status='close'][data-placement^='right'] {
  transform: translateX(-5px);
}

useTransitionStatus() 属性

¥useTransitionStatus() Props

interface UseTransitionStatusProps {
  duration?: number | Partial<{open: number; close: number}>;
}

duration

默认:250

¥default: 250

指定转换的长度(以毫秒为单位)。

¥Specifies the length of the transition in ms.

const {isMounted, status} = useTransitionStatus(context, {
  // Configure both open and close durations:
  duration: 200,
  // Or, configure open and close durations separately:
  duration: {
    open: 200,
    close: 100,
  },
});