官方文档
https://reactcommunity.org/react-transition-group/
安装
cnpm i --save-dev react-transition-group
"react-transition-group": "^4.4.2",
插件中的组件
Transition
CSSTransition
SwitchTransition
TransitionGroup
CSSTransition css过渡组件
分为入场动画和过渡动画
*-enter-active表示想要动画到那些样式
*-exit-active 表示离开之后的动画
属性
classNames属性是在组件进入、退出时应用于组件的动画类名称。每个阶段都会加上后缀,
例如
.fade-enter 入场动画第一帧 .fade-enter-active 入场动画第二帧 .fade-enter-done 入场动画执行完成 .fade-exit 出场动画第一帧 .fade-exit-active 出场动画第二帧 .fade-exit-done 出场动画结束 .fade-appear .fade-appear-active 功能和入场动画一致 需要添加属性appear={true} 首次渲染时执行动画
import './App.css'
import { useState } from 'react'
//引入过渡动画
import { CSSTransition } from 'react-transition-group'
console.log(CSSTransition);
function App() {
let [show, setShow] = useState(true);
let handle = function () {
setShow(!show);
}
return (
App组件
)
}
export default App
.fade-enter,.fade-appear{
opacity: 0;
}
.fade-enter-active,.fade-appear-active{
opacity: 1;
transition: opacity .5s;
}
.fade-exit{
opacity: 1;
}
.fade-exit-active{
opacity: 0;
transition: opacity .5s;
}
.fade-exit-done{
opacity: 0;
}
如果实现多个标签动画使用动画组
TransitionGroup组件
路由组件实现动画
.fade-enter {
opacity: 0;
transform: translateX(100%);
}
.fade-enter-active {
opacity: 1;
transform: translateX(0);
transition: all 500ms;
}
.fade-exit {
opacity: 1;
transform: translateX(0);
}
.fade-exit-active {
opacity: 0;
transform: translateX(-100%);
transition: all 500ms;
}
如何实现路由组件根据路由的进入和离开 控制动画
childFactory 您可能需要在孩子退出时对其应用响应式更新。这通常是通过使用来完成的,cloneElement但是在现有子元素的情况下,该元素已被删除并且消费者无法访问。 如果您确实需要在孩子离开时对其进行更新,您可以提供一个childFactory 来包装每个孩子,即使是那些正在离开的孩子。 类型:Function(child: ReactElement) -> ReactElement 默认:child => child
多个动画切换
// src/App6/RouteConfig.js
export const RouterConfig = [
{
path: '/',
component: HomePage
},
{
path: '/about',
component: AboutPage,
sceneConfig: {
enter: 'from-bottom',
exit: 'to-bottom'
}
},
{
path: '/list',
component: ListPage,
sceneConfig: {
enter: 'from-right',
exit: 'to-right'
}
},
{
path: '/detail',
component: DetailPage,
sceneConfig: {
enter: 'from-right',
exit: 'to-right'
}
}
];
index.js
// src/App6/index.js
const DEFAULT_SCENE_CONFIG = {
enter: 'from-right',
exit: 'to-exit'
};
const getSceneConfig = location => {
const matchedRoute = RouterConfig.find(config => new RegExp(`^${config.path}$`).test(location.pathname));
return (matchedRoute && matchedRoute.sceneConfig) || DEFAULT_SCENE_CONFIG;
};
let oldLocation = null;
const Routes = withRouter(({location, history}) => {
// 转场动画应该都是采用当前页面的sceneConfig,所以:
// push操作时,用新location匹配的路由sceneConfig
// pop操作时,用旧location匹配的路由sceneConfig
let classNames = '';
if(history.action === 'PUSH') {
classNames = 'forward-' + getSceneConfig(location).enter;
} else if(history.action === 'POP' && oldLocation) {
classNames = 'back-' + getSceneConfig(oldLocation).exit;
}
// 更新旧location
oldLocation = location;
return (
React.cloneElement(child, {classNames})}
>
{RouterConfig.map((config, index) => (
))}
);
});
vite工具配置@
export default defineConfig({
plugins: [react()],
resolve:{
alias:{
"@":resolve('src')
}
}
})
react原生项目中配置@
安装@craco/craco
在src同级目录创建文件
// src/App6/index.js
const DEFAULT_SCENE_CONFIG = {
enter: 'from-right',
exit: 'to-exit'
};
const getSceneConfig = location => {
const matchedRoute = RouterConfig.find(config => new RegExp(`^${config.path}$`).test(location.pathname));
return (matchedRoute && matchedRoute.sceneConfig) || DEFAULT_SCENE_CONFIG;
};
let oldLocation = null;
const Routes = withRouter(({location, history}) => {
// 转场动画应该都是采用当前页面的sceneConfig,所以:
// push操作时,用新location匹配的路由sceneConfig
// pop操作时,用旧location匹配的路由sceneConfig
let classNames = '';
if(history.action === 'PUSH') {
classNames = 'forward-' + getSceneConfig(location).enter;
} else if(history.action === 'POP' && oldLocation) {
classNames = 'back-' + getSceneConfig(oldLocation).exit;
}
// 更新旧location
oldLocation = location;
return (
React.cloneElement(child, {classNames})}
>
{RouterConfig.map((config, index) => (
))}
);
});
vite工具配置@
export default defineConfig({
plugins: [react()],
resolve:{
alias:{
"@":resolve('src')
}
}
})