动态过渡问题-反应过渡组/反应路由器

时间:2018-07-07 17:49:40

标签: javascript reactjs react-router css-transitions

我目前正在使用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>
);

0 个答案:

没有答案