前端UI组件【免费下载链接】rsuite A suite of React components .项目地址https://gitcode.com/gh_mirrors/rs/rsuite点击查看免费下载rsuite内置了Animation组件族其中Animation.Transition是自由度最高的底层组件它不绑定任何预设动画而是通过四个阶段 className 与 CSSanimation的配合让你完全掌控进入/退出动画的每个细节。本篇以 transition.md 中的官方示例为主体深入剖析Transition的状态机实现、四个阶段 className 的切换机制并完整复现 Zoom、Flip、Rotate、Bounce 四种自定义动画的完整可运行代码。Transition 在 Animation 组件族中的定位Animation组件族由 src/Animation/index.tsx 统一导出包含 5 个成员组件类型说明Animation.FadeFunctionComponent淡入淡出动画Animation.CollapseComponentType折叠高度/宽度动画Animation.BounceFunctionComponent弹跳动画Animation.SlideFunctionComponent滑入滑出动画Animation.TransitionComponentType自定义动画本文主角其中Fade、Bounce、Slide、Collapse都是基于Transition封装的上层组件——例如 Bounce.tsx 内部就是给Transition传入animation、timeout{300}以及预设的bounce-in/bounce-outclassNameSlide.tsx 则是根据placement拼接出slide-in-right之类的 className。因此理解了Transition就等于理解了整个动画体系的底层原理。四个阶段 className自定义动画的唯一入口Transition的核心设计是动画本身完全交给 CSS组件只负责按状态切换 className。文档明确给出了四个阶段 className 的配置方式exitedClassNamecustom-exited exitingClassNamecustom-exiting enteredClassNamecustom-entered enteringClassNamecustom-entering对应四种状态见 src/Animation/Transition.tsx 的STATUS枚举className触发时机语义exitedClassName退出完成后STATUS.EXITED元素保持隐藏最终态exitingClassName退出动画进行中STATUS.EXITING播放退出动画enteringClassName进入动画进行中STATUS.ENTERING播放进入动画enteredClassName进入完成后STATUS.ENTERED元素保持显示最终态在render()方法中Transition.tsx组件根据当前状态只挂载对应阶段的 className其他 className 会被移除。这意味着你可以在四个类上分别定义不同的animation-name实现进入用一套动画、退出用另一套动画的效果。内置的四个生命周期回调除了 classNameTransition还暴露了 6 个生命周期回调供你在动画关键节点挂接业务逻辑onEnter进入动画开始前触发onEntering进入动画开始后触发onEntered进入动画结束后触发onExit退出动画开始前触发onExiting退出动画开始后触发onExited退出动画结束后触发从源码看Transition.tsxperformEnter/performExit会依次调用这三个回调并通过onTransitionEnd监听animationend或transitionend事件事件完成后才推进到下一状态。值得注意的是Transition.spec.tsx 的测试用例明确验证了依次调用 onEnter/onEntering/onEntered以及依次调用 onExit/onExiting/onExited的行为这套回调顺序是有测试保障的。完整实战一个面板切换四种动画下面复现官方示例完整代码见 transition.md用一个 240×120 的渐变卡片做面板通过四个按钮切换 Zoom / Flip / Rotate / Bounce 四种动画每次点击同时切换show状态让面板在进入和退出时各播放一次动画。组件骨架函数式 children ref 转发import { Animation, Button, ButtonToolbar, Card } from rsuite; const AnimatedPanel React.forwardRef(({ ...props }, ref) ( Card {...props} ref{ref} shaded bordered{false} w{240} h{120} cwhite bglinear-gradient(45deg, #4CAF50, #2196F3) div Card.HeaderCustom Transition/Card.Header Card.BodyClick different buttons to see various animation effects!/Card.Body /div /Card ));注意这里的关键点Animation.Transition的 children 是函数形式(props, ref) ReactNode。组件内部会把当前阶段的 className 合并进props.className并把ref传给你见 Transition.tsx。因此业务组件必须通过React.forwardRef接收并透传refTransition 才能拿到真实 DOM 节点来监听animationend事件。若直接传 React 元素Transition 也会用React.cloneElement自动注入ref和 classNameTransition.tsx两种写法都受测试覆盖。状态与事件处理const App () { const [show, setShow] React.useState(true); const [effect, setEffect] React.useState(zoom); const onChange newEffect { setShow(!show); setEffect(newEffect); }; return ( div Styles / ButtonToolbar Button appearanceprimary onClick{() onChange(zoom)}Zoom/Button Button appearanceprimary onClick{() onChange(flip)}Flip/Button Button appearanceprimary onClick{() onChange(rotate)}Rotate/Button Button appearanceprimary onClick{() onChange(bounce)}Bounce/Button /ButtonToolbar hr / div Animation.Transition exitedClassName{custom-exited custom-${effect}-exited} exitingClassName{custom-exiting custom-${effect}-exiting} enteredClassName{custom-entered custom-${effect}-entered} enteringClassName{custom-entering custom-${effect}-entering} in{show} {(props, ref) AnimatedPanel {...props} ref{ref} /} /Animation.Transition /div /div ); };in属性是动画的开关in{true}触发进入动画in{false}触发退出动画默认值及初始状态逻辑见 Transition.tsx。这里把effect拼进 className实现了同一组件动态切换动画效果的效果。配合unmountOnExit属性退出动画结束后组件会被从 DOM 中卸载Transition.tsx适合弹层、抽屉这类需要彻底移除的场景。CSS 动画定义进入与退出各一套 keyframes官方示例的核心 CSS 如下。通用规则先保证动画时长与缓动一致.custom-exiting, .custom-entering { animation: 0.5s cubic-bezier(0.4, 0, 0.2, 1); animation-fill-mode: forwards; }接着为每个效果分别定义*-entering/*-exiting类指向对应的keyframes下面按效果逐一给出完整代码。Zoom缩放进入从 0.3 倍放大并淡入退出反向收缩淡出。.custom-zoom-exiting { animation-name: zoomOut; } .custom-zoom-entering { animation-name: zoomIn; } keyframes zoomIn { from { opacity: 0; transform: scale3d(0.3, 0.3, 0.3); } 50% { opacity: 1; } } keyframes zoomOut { from { opacity: 1; } 50% { opacity: 0; transform: scale3d(0.3, 0.3, 0.3); } to { opacity: 0; } }Flip翻转使用perspective(400px)配合rotate3d沿 X 轴翻转中途有回弹-20deg → 10deg → -5deg模拟 3D 翻牌效果。.custom-flip-exiting { animation-name: flipOut; } .custom-flip-entering { animation-name: flipIn; } keyframes flipIn { from { opacity: 0; transform: perspective(400px) rotate3d(1, 0, 0, 90deg); } 40% { transform: perspective(400px) rotate3d(1, 0, 0, -20deg); } 60% { opacity: 1; transform: perspective(400px) rotate3d(1, 0, 0, 10deg); } 80% { transform: perspective(400px) rotate3d(1, 0, 0, -5deg); } to { transform: perspective(400px); } } keyframes flipOut { from { transform: perspective(400px); } 30% { opacity: 1; transform: perspective(400px) rotate3d(1, 0, 0, -20deg); } to { opacity: 0; transform: perspective(400px) rotate3d(1, 0, 0, 90deg); } }Rotate旋转围绕 Z 轴旋转 180° 并缩放。.custom-rotate-exiting { animation-name: rotateOut; } .custom-rotate-entering { animation-name: rotateIn; } keyframes rotateIn { from { opacity: 0; transform: rotate3d(0, 0, 1, -180deg) scale(0.3); } 50% { opacity: 1; } } keyframes rotateOut { from { opacity: 1; } to { opacity: 0; transform: rotate3d(0, 0, 1, 180deg) scale(0.3); } }Bounce弹跳进入时先放大再回弹1.1 → 0.9 → 1.03 → 0.97退出时反向弹动后消失。.custom-bounce-exiting { animation-name: bounceOut; } .custom-bounce-entering { animation-name: bounceIn; } keyframes bounceIn { from { opacity: 0; transform: scale3d(0.3, 0.3, 0.3); } 20% { transform: scale3d(1.1, 1.1, 1.1); } 40% { transform: scale3d(0.9, 0.9, 0.9); } 60% { opacity: 1; transform: scale3d(1.03, 1.03, 1.03); } 80% { transform: scale3d(0.97, 0.97, 0.97); } to { opacity: 1; transform: scale3d(1, 1, 1); } } keyframes bounceOut { 20% { transform: scale3d(0.9, 0.9, 0.9); } 50%, 55% { opacity: 1; transform: scale3d(1.1, 1.1, 1.1); } to { opacity: 0; transform: scale3d(0.3, 0.3, 0.3); } }进入/退出的最终落点动画结束后类名切换到enteredClassName/exitedClassName因此还要定义这两个类的静态样式否则元素可能停留在动画中间帧.custom-entered { opacity: 1; } .custom-exited { opacity: 0; }原理Transition 内部的状态机与事件监听从源码结构看Transition是一个基于 5 个状态UNMOUNTED、EXITED、ENTERING、ENTERED、EXITING的状态机组件初始状态in{true}且未开启transitionAppear时直接进入ENTERED不播放动画in{false}且开启unmountOnExit时初始为UNMOUNTEDTransition.tsx。状态推进in变化时在componentDidUpdate中调用performEnter/performExit先把状态切到ENTERING/EXITING挂载对应的 entering/exiting className。动画结束判定onTransitionEnd同时监听animationendanimation为 true 时事件名由 utils.ts 中的getAnimationEnd()根据浏览器嗅探返回webkitAnimationEnd或animationend与一个基于timeout的兜底setTimeoutTransition.tsx两者任一先到都会把状态推进到ENTERED/EXITED并切换 className。卸载与安全回调unmountOnExit开启时退出动画完成后组件返回null从 DOM 卸载setNextCallback与safeSetState机制保证了组件卸载后不再触发回调Transition.tsx。其中timeout的默认值是 1000msTransition.tsx它既是事件监听失败时的兜底也决定了动画最长等待时间而Fade、Bounce、Slide等上层组件的默认timeout为 300ms见 Fade.tsx、Bounce.tsx、Slide.tsx使用时建议让timeout与 CSSanimation-duration保持一致或略大避免动画被提前截断。完整 props 参考Animation.Transition的完整 props 定义见 src/Animation/Transition.tsx官方文档 Animation 总览页 也给出了同名参数表属性类型默认值说明enteredClassNamestring进入动画完成后的 classNameenteringClassNamestring进入动画进行中的 classNameexitedClassNamestring退出动画完成后的 classNameexitingClassNamestring退出动画进行中的 classNameinboolean为 true 时显示并播放进入动画onEnter(node?) void进入动画开始前触发onEntering(node?) void进入动画开始时触发onEntered(node?) void进入动画结束后触发onExit(node?) void退出动画开始前触发onExiting(node?) void退出动画开始时触发onExited(node?) void退出动画结束后触发timeoutnumber(1000)动画等待/兜底时长mstransitionAppearboolean首次挂载且in为 true 时也播放进入动画unmountOnExitboolean退出动画结束后从 DOM 卸载组件animationboolean监听animationendtrue还是transitionendfalse扩展思路基于 Transition 的组合用法封装自己的动画组件仿照 Fade.tsx 与 Bounce.tsx 的模式用useStyles(anim)生成带命名空间前缀的 className再包一层Transition即可沉淀出团队可复用的动画组件。与 rsuite 内置动画对比Animation.Fade/Slide/Bounce/Collapse适用于常见交互当需要 3D 翻转、弹性回弹等定制效果时Transition是唯一能完全自定义动画路径的入口。配合弹层组件unmountOnExittransitionAppear组合常用于Modal、Drawer、Tooltip等需要首屏显示 关闭后彻底卸载的组件确保动画期间事件不会泄漏。本篇以官方 transition.md 示例为主线完整给出了 Zoom / Flip / Rotate / Bounce 四套可复制的动画代码并基于 Transition.tsx 源码解释了状态机与事件监听原理。按照文中代码即可在任意 rsuite 项目中落地一套完全自定义的动画方案。赞分享前端UI组件【免费下载链接】rsuite A suite of React components .项目地址https://gitcode.com/gh_mirrors/rs/rsuite点击查看免费下载相关推荐rsuite Animation 组件实战指南Fade、Collapse、Bounce、Slide 与自定义 Transition 动画rsuite Animation 组件实战指南Fade、Collapse、Bounce、Slide 与自定义 Transition 动画 rsuite 的 A前端UI组件SmartRefreshLayout自定义刷新状态管理从原理到实战SmartRefreshLayout自定义刷新状态管理从原理到实战 一、刷新状态管理痛点与解决方案 你是否还在为下拉刷新状态混乱而困扰SmartRefresUI组件移动开发Rsuite Button 加载状态loading实战指南从属性用法到源码实现原理Rsuite Button 加载状态loading实战指南从属性用法到源码实现原理 本文围绕 Rsuite 组件库中 Button 的 loading 状前端UI组件上一篇hekate压缩包解压工具在Switch上处理ZIP/RAR文件下一篇玩转GPT-SoVITS情感合成三步情感控制完整攻略创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考