Project Icon

react-flip-toolkit

React 动画库 react-flip-toolkit 实现流畅界面过渡

react-flip-toolkit 是一个专注于创建流畅界面过渡的 React 动画库。它支持位置、缩放和透明度动画,提供嵌套缩放变换、FLIP 动画和弹簧效果等功能。该库易用且性能优秀,可与 React Router 集成,适合构建动态的用户界面。

react-flip-toolkit 动画 logo

压缩后大小 MIT 许可证 npm 版本

与其他 React FLIP 库的比较

功能react-flip-movereact-overdrivereact-flip-toolkit
位置动画
缩放动画
透明度动画
父元素大小变化时不扭曲子元素
使用真正的 FLIP 而非克隆和交叉淡化
使用弹簧效果进行动画
支持基于弹簧的交错效果
可与 React 以外的框架一起使用

快速开始

npm install react-flip-toolkityarn add react-flip-toolkit

  1. 用单个 Flipper 组件包裹所有需要动画的子元素,该组件有一个 flipKey 属性,每当需要触发动画时该属性都会变化。

  2. Flipped 组件包裹需要动画的元素,这些组件应该有一个在不同渲染间匹配的 flipId 属性。

目录

可分叉示例

简单示例:展开的 Div

动画方块

在 Code Sandbox 上分叉此示例

import React, { useState } from 'react'
import { Flipper, Flipped } from 'react-flip-toolkit'

const AnimatedSquare = () => {
  const [fullScreen, setFullScreen] = useState(false)
  const toggleFullScreen = () => setFullScreen(prevState => !prevState)

  return (
    <Flipper flipKey={fullScreen}>
      <Flipped flipId="square">
        <div
          className={fullScreen ? 'full-screen-square' : 'square'}
          onClick={toggleFullScreen}
        />
      </Flipped>
    </Flipper>
  )
}

简单示例:两个 Div

2 个动画方块

在 Code Sandbox 上分叉此示例

import React, { useState } from 'react'
import { Flipper, Flipped } from 'react-flip-toolkit'

const Square = ({ toggleFullScreen }) => (
  <Flipped flipId="square">
    <div className="square" onClick={toggleFullScreen} />
  </Flipped>
)

const FullScreenSquare = ({ toggleFullScreen }) => (
  <Flipped flipId="square">
    <div className="full-screen-square" onClick={toggleFullScreen} />
  </Flipped>
)

const AnimatedSquare = () => {
  const [fullScreen, setFullScreen] = useState(false)
  const toggleFullScreen = () => setFullScreen(prevState => !prevState)

  return (
    <Flipper flipKey={fullScreen}>
      {fullScreen ? (
        <FullScreenSquare toggleFullScreen={toggleFullScreen} />
      ) : (
        <Square toggleFullScreen={toggleFullScreen} />
      )}
    </Flipper>
  )
}

简单示例:列表随机排序

列表随机排序

在 Code Sandbox 上分叉此示例

import React, { useState } from 'react'
import { Flipper, Flipped } from 'react-flip-toolkit'
import shuffle from 'lodash.shuffle'

const ListShuffler = () => {
  const [data, setData] = useState([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
  const shuffleList = () => setData(shuffle(data))

  return (
    <Flipper flipKey={data.join('')}>
      <button onClick={shuffleList}> 随机排序</button>
      <ul className="list">
        {data.map(d => (
          <Flipped key={d} flipId={d}>
            <li>{d}</li>
          </Flipped>
        ))}
      </ul>
    </Flipper>
  )
}

列表过渡

通过为卡片的大小和位置变化添加动画,为动态卡片列表增添趣味。

动画列表

在 Code Sandbox 上分叉此示例

交错效果

react-flip-toolkit 库提供了基于弹簧的交错配置,让你能够实现复杂的序列效果。

对于最基本的交错效果,你只需要在 Flipped 元素上添加一个 stagger 布尔属性:

<Flipped flipId={`element-${i}`} stagger>
  <AnimatedListItem/>
</Flipped>
列表项选中状态的动画

在 Code Sandbox 上分叉此示例

弹簧自定义

react-flip-toolkit 使用弹簧动画。要自定义弹簧效果,你可以传入一个预设名称:

// 弹簧预设可以是以下之一: "stiff", "noWobble", "gentle", "veryGentle", 或 "wobbly"
<Flipper flipKey='foo' spring='wobbly'>
  {/* 放置 Flipped 组件 */}
</Flipper>

或者自定义弹簧配置:

<Flipper flipKey='foo' spring={{ stiffness: 280, damping: 22 }} >
  {/* 放置 Flipped 组件 */}
</Flipper>

在交互式探索器中查看所有弹簧选项

嵌套缩放变换

stripe 菜单

有趣的动画通常除了简单的平移变换外还包含缩放变换。缩放动画的问题在于子元素 — 如果你将一个 div 放大 2 倍,它的任何子元素也会被放大,从而创建一个看起来很奇怪的动画。这就是为什么这个库允许你用一个带有 inverseFlipIdFlipped 组件包裹子元素,以抵消父元素的变换:

<Flipped flipId={id}>
  <div>
    <Flipped inverseFlipId={id} scale>
      <div>不会被扭曲的文本</div>
    </Flipped>
  </div>
</Flipped>

默认情况下,父元素的缩放和平移变换都会被抵消(这允许子组件进行自己的 FLIP 动画而不受父元素影响)。 但在许多使用场景中,你还需要额外指定 scale 属性来限制调整为仅缩放,并允许定位随父元素移动。

注意: 具有反向变换的 DOM 元素应该紧贴其父容器,以实现最无缝的动画效果。

这意味着任何布局样式 — 内边距、弹性盒子等 — 应该应用于反转容器(用带有 inverseFlipIdFlipped 组件包裹的元素)而不是父 Flipped 容器。

使用 React Router 的基于路由的动画

React-flip-toolkit 与 React-Router

Fork GitHub 仓库

react-flip-toolkit 可以很好地与客户端路由器配合使用,提供路由驱动的过渡效果:

<Route
  render={({ location, search }) => {
    return (
      <Flipper
        flipKey={`${location.pathname}-${location.search}`}
      >
      {/* 包含 Flipped 组件的子路由放在这里 */}
      </Flipper>
    )
  }}
/>

更多示例

组件

Flipper

包含所有需要动画的元素的父包装组件。通常每个页面只需要一个,但有时在页面的不同区域使用多个 Flipper 来处理不同的过渡效果会更方便。

<Flipper flipKey={someKeyThatChanges}>{/* 子元素 */}</Flipper>

基本属性

属性默认值类型详情
flipKey (必填)-string, number, bool改变这个值会告诉 react-flip-toolkit 对包裹在 Flipped 组件中的子元素进行过渡。
children (必填)-node一个或多个元素子节点
springnoWobblestringobject提供一个字符串引用预设弹簧之一 — noWobble(默认), veryGentle, gentle, wobbly, 或 stiff, 或者提供一个包含 stiffness 和 damping 参数的对象。在这里探索弹簧设置选项。这里提供的属性将作为默认弹簧设置,可以在 Flipped 组件上针对每个元素进行覆盖。
applyTransformOrigintrueboolreact-flip-toolkit 是否应该为动画子元素应用 "0 0" 的 transform-origin (这通常但并不总是适用于 FLIP 动画)
elementdivstring如果你想让 Flipped 容器创建的包装元素是 div 以外的其他元素,可以在这里指定。
className-string应用于包装元素的类名,有助于样式设置。
staggerConfig-object为交错的 Flipped 子元素提供配置。配置对象可能看起来像下面的代码片段:
staggerConfig={{
  // "default" 配置将应用于没有显式键的交错元素
      default: {
        // 默认方向是正向
        reverse: true,
        // 默认为 .1, 0 < n < 1
        speed: .5
      },
  // 这将应用于具有 stagger='namedStagger' 属性的 Flipped 元素
    namedStagger : { speed: .2 }
  }}

高级属性

属性默认值类型详情
decisionData-any有时,你可能希望 Flipper 的动画子元素根据状态转换表现不同 — 也许只有某些 Flipped 元素应该响应特定的变化进行动画。通过为 Flipper 组件提供 decisionData 属性,你可以使该数据在每个子 Flipped 组件的 shouldFlipshouldInvert 方法中可用,这样它们可以自行决定是否进行动画。
debugfalseboolean这个实验性属性会在 FLIP 样式初始应用时暂停你的动画。这允许你在动画开始时检查状态,此时应该看起来与动画开始前的 UI 相似或相同。
portalKey-string通常,Flipper 组件只会对其后代应用过渡效果。这允许多个 Flipper 元素在同一页面上共存,但如果你使用 portals,它会阻止动画工作。你可以为 Flipper 提供一个唯一的 portalKey 属性,告诉它将元素选择范围扩大到整个文档,而不仅限于其子元素,这样 portals 中的元素也可以进行过渡。
onStart-function这个回调属性会在任何单独的 FLIP 动画开始之前被调用。它接收 Flipper 的 HTMLElement 和前面描述的 decisionData 对象作为参数。
onComplete-function这个回调属性会在所有单独的 FLIP 动画完成时被调用。它的唯一参数是在动画过程中被激活的 Flipped 组件的 flipId 列表。如果动画被中断,onComplete 仍会在正在进行的动画终止之前被调用。
handleEnterUpdateDelete-function默认情况下,react-flip-toolkit 会在动画新元素之前完成退出元素的动画,同时更新元素会立即变换。你可能想要对过渡序列有更多控制 — 比如,你想隐藏元素,暂停,更新元素,再次暂停,最后动画显示新元素。或者你可能希望过渡同时发生。如果是这样,请提供 handleEnterUpdateDelete 函数作为属性。理解其工作原理的最佳方式是查看这个交互式示例。 每次发生过渡时,handleEnterUpdateDelete 都会接收以下参数:
handleEnterUpdateDelete({
  // 该函数将进入元素的不透明度设为0,以便后续淡入效果
  // 应该立即调用
  hideEnteringElements,
  // 为所有进入的元素调用 `onAppear`
  animateEnteringElements,
  // 为所有退出的元素调用 `onExit`
  // 返回一个 Promise,在所有元素退出后解析
  animateExitingElements,
  // 主要事件:对更新的元素执行 `FLIP` 动画
  // 同样返回一个 Promise,在动画完成时解析
  animateFlippedElements
})

Flipped

包装一个需要动画效果的元素。

例如,在一个组件中你可以有:

<Flipped flipId="coolDiv">
  <div className="small" />
</Flipped>

在另一个组件的其他地方你可以有:

<Flipped flipId="coolDiv">
  <div className="big" />
</Flipped>

它们将通过 react-flip-toolkit 进行过渡动画。

Flipped 组件不会生成任何标记,它只是将一些属性传递给其包装的子元素。

包装 React 组件

如果你想包装 React 组件而不是像 div 这样的 JSX 元素,你可以提供一个渲染属性,然后在你的组件中将 flippedProps 直接应用到被包装的元素上:

<Flipped>
  {flippedProps => <MyCoolComponent flippedProps={flippedProps} />}
</Flipped>

const MyCoolComponent = ({ flippedProps }) => <div {...flippedProps} />

你也可以简单地提供一个普通的 React 组件,只要该组件将未识别的属性直接传递给包装的元素(这种技术适用于包装样式化组件):

<Flipped>
  <MyCoolComponent />
</Flipped>

const MyCoolComponent = ({ knownProp, ...rest }) => <div {...rest} />

基本属性

属性默认值类型详情
children (必需)-nodefunctionFlipped 组件包装单个元素、React 组件或渲染属性子元素
flipId (除非提供 inverseFlipId,否则为必需)-string用于告诉 react-flip-toolkit 如何在渲染之间匹配元素,以便进行动画处理。
inverseFlipId-string引用父 Flipped 容器的 id,其变换你想要抵消。如果提供此属性,Flipped 组件将成为其有限版本,仅负责抵消其父变换。它将读取任何提供的 transform 属性,并忽略所有其他属性(除了 inverseFlipId)。在此处阅读更多关于抵消父变换的信息。
transformOrigin"0 0"string这是一个便捷方法,用于将正确的 CSS transform-origin 应用于被 FLIP 的元素。如果作为属性提供,这将覆盖 react-flip-toolkit 默认应用的 transform-origin: 0 0;
springnoWobblestringobject提供一个字符串引用预设的弹簧之一 — noWobble(默认)、veryGentlegentlewobblystiff,或者提供一个包含 stiffness 和 damping 参数的对象。在此处探索弹簧设置选项。
staggerfalsebooleanstring提供一个自然的、基于弹簧的错开效果,其中每个项目的弹簧缓动都固定在前一个的移动上。提供 true 以将元素与所有其他错开的元素错开。如果你想更精细地控制,可以提供一个字符串键,元素将与具有相同键的其他元素错开。
delayUntilfalsestring (flipId)通过提供对另一个 Flipped 组件的引用来延迟动画,它应该等待该组件后再开始动画(另一个 Flipped 组件应该有错开延迟,因为这是唯一需要此属性的用例。)

回调属性

一个句子变形为另一个句子的动画

上面的动画使用 onAppearonExit 回调来实现淡入和淡出动画。

属性参数详情
onAppearelement, index, {previous: decisionData, current: decisionData }当元素首次出现在 DOM 中时调用。第一个参数提供正在过渡的 DOM 元素的引用,第二个参数是元素相对于所有出现元素的索引。注意:如果你提供 onAppear 属性,元素的默认不透明度将被设置为 0,以允许你将其动画化而不会有任何初始闪烁。如果你不想要任何不透明度动画,只需在 onAppear 函数中立即将元素的不透明度设置为 1。
onStartelement, {previous: decisionData, current: decisionData }当元素的 FLIP 动画开始时调用。第一个参数提供正在过渡的 DOM 元素的引用。
onStartImmediateelement, {previous: decisionData, current: decisionData }类似于 onStart,但保证在 FLIP 动画的初始刻度上为所有 FLIP 元素运行,在下一帧渲染之前,即使元素有错开延迟。第一个参数提供正在过渡的 DOM 元素的引用。
onSpringUpdatespringValue使用当前的弹簧值调用(通常在 0 - 1 之间,但可能根据弹簧的"弹性"程度短暂超出或低于该范围)。如果你想要与 FLIP 过渡同时调整其他非 FLIP 动画,这个属性很有用。
onCompleteelement,{previous: decisionData, current: decisionData }当 FLIP 动画完成时调用。第一个参数提供正在过渡的 DOM 元素的引用。(如果过渡被新的过渡打断,onComplete 仍会被调用。)
onExitelement, index, removeElement, {previous: decisionData, current: decisionData }当元素从 DOM 中移除时调用。它必须在退出过渡完成时调用 removeElement 函数。

变换属性

默认情况下,FLIP 元素的 translate、scale 和 opacity 属性都会被变换。但是,某些效果需要更多控制,所以如果你指定了以下任何属性,只有指定的属性会被缓动

属性类型详情
translatebool缓动 translateXtranslateY
scalebool缓动 scaleXscaleY
opacitybool

高级属性

控制 FLIP 何时发生的函数

属性参数详情
shouldFlippreviousDecisionData, currentDecisionData一个函数,提供由 Flipper 组件传递的当前和之前的 decisionData 属性。返回一个 boolean 值,表示 Flipped 组件在特定时刻是否应该动画化。
shouldInvertpreviousDecisionData, currentDecisionData一个函数,提供由 Flipper 组件传递的当前和之前的 decisionData 属性。返回一个 boolean 值,表示是否对所有通过 inverseFlipId 请求的 Flipped 子元素应用反转变换。

Spring

为了方便,react-flip-toolkit 导出了一个小函数,用于访问用于创建 FLIP 过渡的相同弹簧系统。

在 CodeSandbox 上 Fork 示例

import { spring } from 'react-flip-toolkit'

spring({
  config: "wobbly",
  values: {
    translateY: [-15, 0],
    opacity: [0, 1]
  },
  onUpdate: ({ translateY, opacity }) => {
    el.style.opacity = opacity;
    el.style.transform = `translateY(${translateY}px)`;
  },
  delay: i * 25,
  onComplete: () => console.log('完成')
});
弹簧示例

全局配置函数

如果需要在所有地方禁用(或重新启用)FLIP动画,可以通过编程方式调用以下函数。

disableFlip()

全局开关,用于禁用所有Flipper容器中的所有动画。

enableFlip()

全局开关,用于(重新)启用所有Flipper容器中的所有动画。默认情况下,动画是启用的。只有在之前使用disableFlip()禁用了动画时,才需要调用此函数。

isFlipEnabled()

返回一个布尔值,指示动画是全局启用还是禁用。

库详情

browserstack
  • 使用Browserstack在最新的Chrome、Firefox、Safari和Edge浏览器中进行了测试。
  • 需要React 16+版本
  • 使用Rematrix进行矩阵计算,使用Rebound的简化分支进行弹簧动画

故障排除

问题#1:没有任何反应

  • 确保在需要触发动画时更新了Flipper组件的flipKey属性。
  • 如果你的Flipped组件包裹的是另一个React组件而不是DOM元素,使用渲染属性获取Flipped属性并传递给必要的DOM元素。
  • 接收Flipped属性的元素是否在DOM中可见?react-flip-toolkit会尝试优化性能,不会对屏幕外的元素或没有宽度和高度的元素进行动画处理。
  • display:inline元素无法进行动画。如果你想让inline元素产生动画效果,请设置display:inline-block
  • 你是否开启了prefers-reduced-motion设置?从v7.1.0版本开始,该设置会禁用所有动画。

问题#2:效果看起来很奇怪/动画行为异常

  • 检查确保所有flipId是唯一的。 在任何时候,页面上只能有一个元素具有指定的flipId。如果页面上有多个具有相同id的Flipped元素,动画将会出错。
  • 确保你在为想要制作动画的元素添加动画,而不是例如包裹它的div。 如果你为内联元素(如文本)制作动画,但将其包裹在一个div中,实际上你是在为div添加动画,这可能会在某些时候导致宽度比预期的要大得多,从而影响动画效果。检查是否需要给动画元素添加inline-block样式。
  • 确保相关元素上没有任何冲突的CSS过渡
  • 如果你在为图片制作动画,尝试给图片设置固定尺寸,看看是否能解决问题。(如果你依赖图片的固有尺寸,可能在浏览器完全渲染新图片尺寸之前就开始测量了。)

问题#3:仍然无法正常工作

  • 尝试使用debug属性。如果你仍然无法找出问题所在,可以直接在Flipper组件上添加debug属性来暂停过渡的开始。
  • 如果你认为可能确实存在问题,或者完全卡住了,欢迎提出issue。

性能

React-flip-toolkit在底层做了很多工作来尝试最大化你的动画性能 —— 例如,不会对屏幕外的元素进行动画处理,并且样式更新会被批量处理以防止布局抖动。 然而,如果你正在构建特别复杂的动画 —— 涉及数十个元素或大型图片的动画 —— 还有一些额外的策略可以用来确保动画的性能。

记忆化

当你使用react-flip-toolkit触发复杂的FLIP动画时,React可能会在允许动画开始之前花费宝贵的毫秒时间进行不必要的协调工作。如果你注意到动画触发和开始之间有轻微的延迟,这可能就是原因。为了绕过这种可能不必要的工作,尝试使用React.memoPureComponent对你的动画元素进行记忆化,并看看是否可以重构你的代码,以在动画即将发生时最小化对动画子元素的属性更新。

will-change:transform

.box {
  will-change: transform;
}

这个CSS属性告诉浏览器预期元素将发生变化。应谨慎使用,因为它可能会增加浏览器资源的使用。如果你注意到动画中存在渲染问题,可以尝试看看它是否能提高动画的性能。

项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号