如何在关闭Panel组件时实现入场动画的反向效果?
解决React Spring Panel关闭时无反向动画的问题
要实现关闭时的反向退场动画,核心是让动画完成后再执行组件卸载,同时根据显示状态动态切换动画目标。以下是具体方案:
关键改动点
- 新增
isOpenprops,用于控制Panel的显示状态(由父组件传入,不再直接卸载组件) - 根据
isOpen动态设置useSpring的目标值,关闭时触发反向动画 - 监听动画结束事件,待退场动画完成后再调用
onClose通知父组件更新状态
修改后的完整代码
import { useSpring, animated } from 'react-spring'; import { CgClose } from 'react-icons/cg'; import clsx from 'clsx'; type PanelProps = { children: React.ReactNode; onClose: () => void; classNames?: { panelSize?: string; }; isOpen: boolean; // 新增控制显示的props }; const Panel: React.FC<PanelProps> = ({ children, onClose, classNames, isOpen }) => { const transitions = useSpring({ transform: isOpen ? "translateX(0)" : "translateX(100%)", from: { transform: "translateX(100%)" }, config: { duration: 200 }, onRest: () => { // 动画结束后,若处于关闭状态则调用onClose if (!isOpen) { onClose(); } }, }); // 动画完成且已关闭时,才销毁组件 if (!isOpen && !transitions.transform.isAnimating) { return null; } return ( <div className='z-10 lg:fixed lg:left-0 lg:top-0 lg:flex lg:h-screen lg:w-screen'> {/* 遮罩层添加渐隐动画优化体验 */} <animated.div onClick={() => !transitions.transform.isAnimating && onClose()} className='w-full bg-black' style={{ opacity: isOpen ? 0.4 : 0, transition: 'opacity 200ms' }} /> <animated.div className={clsx( "fixed right-0 top-0 z-10 h-screen w-full overflow-y-auto bg-white shadow-lg", classNames?.panelSize ?? "w-full md:w-4/12" )} style={transitions}> <button onClick={() => !transitions.transform.isAnimating && onClose()} className='absolute right-6 top-6 rounded-full bg-white p-1 duration-100 ease-in hover:scale-125 '> <CgClose size={20} /> </button> <div>{children}</div> </animated.div> </div> ); }; export default Panel;
父组件配合示例
父组件需要维护isOpen状态,通过状态更新控制面板显示/隐藏,而非直接卸载组件:
import { useState } from 'react'; import Panel from './Panel'; const ParentComponent = () => { const [isPanelOpen, setIsPanelOpen] = useState(false); return ( <div> <button onClick={() => setIsPanelOpen(true)}>打开面板</button> <Panel isOpen={isPanelOpen} onClose={() => setIsPanelOpen(false)} > {/* 面板内容 */} <p>这是右侧面板的内容</p> </Panel> </div> ); }; export default ParentComponent;
额外说明
- 点击关闭按钮和遮罩层时,先判断动画是否正在执行,避免重复触发导致的异常
- 遮罩层的渐隐动画是可选优化,让整体交互更流畅
- 通过
onRest回调确保动画完全结束后才通知父组件,保证退场动画完整播放
内容的提问来源于stack exchange,提问作者Johan
相关产品推荐
相关产品推荐

