使用场景
在使用React router dom
进行路由切换的时候,视图会直接切换,导致观感过于生硬,由此可以添加过渡动画,使过渡更加平滑。以下是两种可能的实现方案以供参考。
1. 组件懒加载+Suspense
React
组件在被挂载可视前会执行一系列生命周期函数,如果待加载的组件被Suspense
组件包裹,那组件在加载完毕前会被Suspense
中设置的组件替代显示。
jsx
<Suspense fallback={<Loading/>}>
<MyComponent />
</Suspense>
这段代码实现的效果就是MyComponent
组件在加载的时候会显示Loading
的内容。
因此可以使用懒加载路由组件并用Suspense
包裹所有路由组件的方法实现一个简单的过渡动画:
JSX
// 路由配置文件
const Home=lazy(()=>import("../pages/Home/index.tsx"));
const routes=[
{
path:"/",
element:<Home />
}
]
// 路由挂载的组件
export default function Main() {
const elements=useRoutes(routes);
return (
<main>
<Suspense fallback={<Loading/>}>
{elements}
</Suspense>
</main>
)
}
使用ECharts
实现的一个简单Loading
做测试
JSX
export default function Loading() {
const loadingRef=useRef(null);
useEffect(()=>{
let loading=echarts.init(loadingRef.current);
const option:EChartsOption = {
graphic: {
elements: [
{
type: 'group',
left: 'center',
top: 'center',
children: new Array(7).fill(0).map((val, i) => ({
type: 'rect',
x: i * 20,
shape: {
x: 0,
y: -40,
width: 10,
height: 80
},
style: {
fill: '#ffffff'
},
keyframeAnimation: {
duration: 1000,
delay: i * 200,
loop: true,
keyframes: [
{
percent: 0.5,
scaleY: 0.3,
easing: 'cubicIn'
},
{
percent: 1,
scaleY: 1,
easing: 'cubicOut'
}
]
}
}))
}
]
}
};
loading.setOption(option);
},[])
return (
<div ref={loadingRef} className={'loading-main'} />
);
}
现在在路由页面切换时,这个Loading
组件会显示,当组件加载完成时,Loading
组件也会被正常卸载。
但美中不足的一点就是Loading
这个组件本身也会没有过渡地突然出现和消失。我之前想过使用React
的生命周期函数来动态控制CSS(添加复合类的形式),类似:
SCSS
.loading{
// 其他样式...
transition: 0.3s;
&.fade-in{
opacity: 1;
// 其他样式...
}
&.fade-out{
opacity: 0;
// 其他样式...
}
}
然后在componentDidMount
时添加fade-in
,在componentWillUnMount
的时候添加fade-out
实现Loading
组件本身的过渡效果,后面测试时发现这种方法并不可行,经过搜索和自己测试,最终采取了下面的方式解决。
2. 使用react-transition-group
库
react-transition-group\]([react-transition-group - npm](https://link.juejin.cn?target=https%3A%2F%2Fwww.npmjs.com%2Fpackage%2Freact-transition-group "https://www.npmjs.com/package/react-transition-group"))是管理组件的挂载和卸载,并提供生命周期钩子来应用CSS动画或JavaScript动画的库,使用其可以实现比较完美的过渡动画
*
### 安装
```shell
npm install react-transition-group --save
```
*
### 使用
创建两个state用于管理动画状态
```TSX
const [isLoading, setIsLoading] = useState(false);
const [showLoading, setShowLoading] = useState(false);
```
再监测路由跳转,当路由变化时设置显示`Loading`组件并开始动画
```TSX
useEffect(() => {
setIsLoading(true);
setShowLoading(true);
loadingStartTime.current = Date.now();
}, [location.key]);
```
在所有路由组件的最外层使用`CSSTransition`包裹
```TSX