需要实现的效果:
类似antd组件中的折叠面板的折叠动画
遇到的问题:
css原生不支持,从height:0到height:auto的过渡(因为auto是代表一个不确定的值, 过渡动画需要明确的开始值和结束值)
依赖: npm install react-transition-group
实现代码:
import React, { useRef, useState } from 'react';
import { Transition } from 'react-transition-group';
const duration = 300; // 动画持续时间
const defaultStyle = {
transition: `height ${duration}ms ease-in-out`,
overflow: 'hidden',
};
const transitionStyles = {
entering: { height: 0 },
entered: { height: 'auto' }, // 动画结束后设置为 auto
exiting: { height: 'auto' }, // 开始退出动画之前设置为 auto
exited: { height: 0 },
};
const Collapsible = ({ children }) => {
const [isOpen, setIsOpen] = useState(false);
const contentRef = useRef(null);
return (
<>
<button onClick={() => setIsOpen(!isOpen)}>
{isOpen ? 'Collapse' : 'Expand'}
</button>
<Transition
in={isOpen}
timeout={duration}
onEntering={node => {
// 动态获取内容高度并应用,创建展开动画
node.style.height = `${node.scrollHeight}px`;
}}
onEntered={node => {
// 动画结束后重置高度, 以支持内容动态变化的自适应
node.style.height = 'auto';
}}
onExit={node => {
// 强制 reflow,获取实际高度值作为最初状态
node.style.height = `${node.scrollHeight}px`;
}}
onExiting={node => {
// 强制 reflow,设置高度为0开始收缩动画
node.offsetHeight; // eslint-disable-line no-unused-expressions
node.style.height = '0';
}}
>
{state => (
<div
ref={contentRef}
style={{
...defaultStyle,
...transitionStyles[state]
}}
>
{children}
</div>
)}
</Transition>
</>
);
};
export default Collapsible;