我目前正在使用React,React Transition Group和React Router DOM创建我的Portfolio网站。我的所有动画目前似乎都可以正常运行-只要它们不会被Android设备上的 back 按钮或 back 和<浏览器上的em>前进按钮。
可以在此处查看网站:https://victorevan.github.io/Portfolio/
源代码位于:https://github.com/VictorEvan/Portfolio
我的动画通过读取location.pathname来确定要 来自 的动画的页面,以及要确定 要的动画的页面< / strong>。这在我的childFactoryCreator函数中处理。它调用我的animationHandler函数以返回适当的classNames,超时并在解构后显示为布尔值。它将这些值返回给要渲染的子组件。
传递了所有适当的动画,但是如果用户在过渡期间单击后退按钮或前进按钮,则会传递错误的className,并且站点将中断。我想我想知道的是,是否有更好的方法来处理这些动态过渡,或者有创造性的解决方案来处理用户过渡中断。
childFactoryCreator:
render() {
const childFactoryCreator = () => {
let animateFromPage = this.state.animateFromPage;
let animateToPage = this.props.location.pathname;
console.log(this.animationHandler(animateFromPage, animateToPage));
let { classNames, timeout, appear } = this.animationHandler(animateFromPage,animateToPage);
return (
(child) => {
return ( React.cloneElement(child, { classNames, timeout, appear }) )
}
);
}
animationHandler:
animationHandler = (from, to) => {
if (from !== to) {
// from switch
const repetitiveProjects = {
'/portfolio/tic-tac-toe': true,
'/portfolio/calculator': true,
'/portfolio/random-quote-generator': true,
'/portfolio/pomodoro-clock': true
}
if (repetitiveProjects[from] && to !== '/contact') from = 'any-project'
switch(from) {
case '/contact':
return {
classNames: {
enter: '',
enterActive: '',
enterDone: '',
exit: 'move-out-halves',
exitActive: 'move-out-halves-active',
exitDone: ''
}, timeout: 1250, appear: false
}
case 'any-project':
return {
classNames: 'fade', timeout: 500, appear: false
}
default:
break;
}
// to switch
switch(to) {
case '/contact':
return {
classNames: {
enter: 'move-in-halves',
enterActive: 'move-in-halves-active',
enterDone: '',
exit: '',
exitActive: '',
exitDone: ''
}, timeout: 1500, appear: false
}
default:
break;
}
}
// full from to switch
const data = `${from}-${to}`;
switch(data) {
case '/-/portfolio':
return {
classNames: {
enter: 'slide-up-from-bottom',
enterActive: 'slide-up-from-bottom-active',
enterDone: '',
exit: 'slide-up-from-middle',
exitActive: 'slide-up-from-middle-active',
exitDone: 'slide-up-from-middle-done'
},
timeout: 1500, appear: false
}
case '/portfolio-/':
return {
classNames: {
enter: 'slide-down-from-top',
enterActive: 'slide-down-from-top-active',
enterDone: '',
exit: 'slide-down-from-middle',
exitActive: 'slide-down-from-middle-active',
exitDone: 'slide-down-from-middle-done'
},
timeout: 1500, appear: false
}
case `/portfolio-/portfolio/${this.props.projects[0].title}`:
return {
classNames: {
enter: 'fade-enter',
enterActive: 'fade-enter-active--delay',
enterDone: '',
exit: 'expand-project--project-one',
exitActive: 'expand-project--project-one-active',
exitDone: ''
},
timeout: 1500, appear: false
}
case `/portfolio-/portfolio/${this.props.projects[1].title}`:
return {
classNames: {
enter: 'fade-enter',
enterActive: 'fade-enter-active--delay',
enterDone: '',
exit: 'expand-project--project-two',
exitActive: 'expand-project--project-two-active',
exitDone: ''
},
timeout: 1500, appear: false
}
case `/portfolio-/portfolio/${this.props.projects[2].title}`:
return {
classNames: {
enter: 'fade-enter',
enterActive: 'fade-enter-active--delay',
enterDone: '',
exit: 'expand-project--project-three',
exitActive: 'expand-project--project-three-active',
exitDone: ''
},
timeout: 1500, appear: false
}
case `/portfolio-/portfolio/${this.props.projects[3].title}`:
return {
classNames: {
enter: 'fade-enter',
enterActive: 'fade-enter-active--delay',
enterDone: '',
exit: 'expand-project--project-four',
exitActive: 'expand-project--project-four-active',
exitDone: ''
},
timeout: 1500, appear: false
}
default:
return {
classNames: {
enter: '',
enterActive: '',
enterDone: '',
exit: '',
exitActive: '',
exitDone: ''
},
timeout: 0, appear: false
}
}
}
渲染返回值:
return (
<div className='app'>
<Header
location={this.props.location}
isAnimating={this.state.pageIsAnimating}
/>
<TransitionGroup
component={null}
childFactory={childFactoryCreator()}
>
<CSSTransition
key={this.props.location.pathname}
timeout={0}
onEnter={() => {
// console.log(`onEnter: A <Transition> callback fired immediately after the 'enter' or 'appear' class is applied.`);
document.body.style.overflow = "hidden";
this.setState({pageIsAnimating: true});
}}
// onEntering={() => console.log(`onEntering: A <Transition> callback fired immediately after the 'enter-active' or 'appear-active' class is applied.`)}
onEntered={() => {
// console.log(`onEntered: A <Transition> callback fired immediately after the 'enter' or 'appear' classes are removed and the done class is added to the DOM node.`);
if (this.props.location.pathname === '/') this.setState({pageIsAnimating: false});
}}
// onExit={() => console.log(`onExit: A <Transition> callback fired immediately after the 'exit' class is applied.`)}
// onExiting={() => console.log(`onExiting: A <Transition> callback fired immediately after the 'exit-active' is applied.`)}
onExited={() => {
// console.log(`onExited: A <Transition> callback fired immediately after the 'exit' classes are removed and the exit-done class is added to the DOM node.`);
// set the current Page to be the animateFromPage going forward
setTimeout( () => {
this.setState({animateFromPage: this.props.location.pathname, pageIsAnimating: false});
},0 );
document.body.style.overflow = "auto";
}}
>
<Switch location={this.props.location}>
<Route exact path={`/`} render={props =>
<Intro
{...props}
isAnimating={this.state.pageIsAnimating}
/>}
/>
<Route exact path={`/portfolio`} render={props =>
<Portfolio
{...props}
projects={this.props.projects}
/>}
/>
<Route exact path={`/contact`} render={props =>
<About
{...props}
/>}
/>
{this.props.projects.map( project => (
<Route key={project.title} exact path={`/portfolio/${project.title}`} render={props =>
<CaseStudy
{...props}
project={project}
/>}
/>
))}
</Switch>
</CSSTransition>
</TransitionGroup>
</div>
);