接上篇文章 React动画(中)
1,封装举例
封装一个渐入渐出效果的动画组件
import { CSSTransition } from "react-transition-group";
import "./FadeTransition.css";
export default function FadeTransition(props) {
return <CSSTransition {...props}>{props.children}</CSSTransition>;
}
/* FadeTransition.css */
.appear {
opacity: 0;
}
.appear-active {
opacity: 1;
transition: opacity 1s;
}
.enter {
opacity: 0;
}
.enter-active {
opacity: 1;
transition: opacity 1s;
}
.exit-active {
opacity: 0;
transition: opacity 1s;
}
.exit-done {
opacity: 0;
}
使用:
import { useState } from "react";
import FadeTransition from "./FadeTransition";
export default function App() {
const [state, setState] = useState(true);
return (
<>
<button onClick={() => setState(!state)}>{state ? "隐藏" : "显示"}</button>
<FadeTransition in={state} appear timeout={1000}>
<h1>标题1</h1>
</FadeTransition>
</>
);
}
2,问题
2.1,timeout
可以看到,传递的 timeout
需要和 css 中的过渡时间保持一致。
解决:将 css 文件中设置的 transition
属性都移除掉,通过内联样式设置。
内联样式通过钩子函数来设置:
import { CSSTransition } from "react-transition-group";
import "./FadeTransition.css";
FadeTransition.defaultProps = {
timeout: 500,
};
const addTransition = (node, timeout) => {
node.style.transition = `opacity ${timeout}ms`;
};
const removeTransition = (node) => {
node.style.transition = "";
};
export default function FadeTransition(props) {
return (
<CSSTransition
{...props}
onEnter={(node) => addTransition(node, props.timeout)}
onEntered={(node) => removeTransition(node)}
onExit={(node) => addTransition(node, props.timeout)}
onExited={(node) => removeTransition(node)}
>
{props.children}
</CSSTransition>
);
}
2.2,配合 SwitchTransition / TransitionGroup
SwitchTransition 组件会调用 CSSTransition 组件的 onExited
方法,让下个元素执行进入动画,所以需要执行传入的 props.onExited(node)
。
其实,这几个动画组件在不同的动画状态,添加对应的类名,都是在这些钩子函数中实现的。
export default function FadeTransition(props) {
return (
<CSSTransition
{...props}
onEnter={(node) => addTransition(node, props.timeout)}
onEntered={(node) => removeTransition(node)}
onExit={(node) => addTransition(node, props.timeout)}
onExited={(node) => {
removeTransition(node);
props.onExited && props.onExited(node);
}}
>
{props.children}
</CSSTransition>
);
}
使用:
export default function App() {
const [state, setState] = useState(true);
return (
<>
<button onClick={() => setState(!state)}>切换</button>
<SwitchTransition>
<FadeTransition key={state} appear timeout={1000}>
<h1>{state ? "标题1" : "标题2"}</h1>
</FadeTransition>
</SwitchTransition>
</>
);
}
TransitionGroup 同理,不再赘述。
以上。