React:如何为页面转换添加动画效果

5
我想知道如何在React.js中实现一个动画组件/页面切换,希望能够像http://www.semplicelabs.com/上的过渡效果一样 - 一个标题过渡透明度和margin-top,一个内容过渡透明度。当显示新的组件/页面时,当前显示的组件/页面应该在新的组件/页面过渡进入之前过渡出去。我目前拥有的是一个LayoutComponent,它将页面组件呈现到CSSTransitionGroup中。
import React from 'react/addons';

export default class LayoutComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { page: '' };
  },

  setPage(page) {
    this.setState({ page });
  }

  render() {
    return (
      <React.addons.CSSTransitionGroup transitionName='page'>
        {this.state.page}
      </React.addons.CSSTransitionGroup>
    );
  }
}

我还有两个页面组件,FirstPageSecondPage
import React from 'react';

export default class FirstPage extends React.Component {
  render() {
    return (
      <div>
        <header className='header'>
          <div className='container'>
            First Header
          </div>
        </header>
        <div className='content'>
          <div className='container'>
            First Content
          </div>
        </div>
      </div>
    );
  }
}

SecondPage 代码和 FirstPage 代码唯一的区别在于 .container div 中的内容和类名。

接下来我尝试添加一个 .8s 持续时间的离开过渡和一个既有 .8s 持续时间又有延迟的进入过渡。我看到的主要问题是新页面组件在旧页面的离开过渡完成之前就已经挂载了。这是我的当前 CSS:

.page-enter {
  background-color: #f2f2f2;
  transition: background-color .8s linear .8s;
}

.page-enter-active {
  background-color: #f2f1f1;
}

.page-leave {
  background-color: #f2f1f1;
  transition: background-color .8s linear;
}

.page-leave-active {
  background-color: #f2f2f2;
}

.page-enter .header {
  margin-top: -80px;
  opacity: 0;
  transition: opacity .8s ease-in-out .8s;
  transition: margin-top .8s ease-in-out .8s;
}

.page-enter-active .header {
  margin-top: 0;
  opacity: 1;
}

.page-leave .header {
  margin-top: 0;
  opacity: 1;
  transition: opacity .8s ease-in-out;
  transition: margin-top .8s ease-in-out;
}

.page-leave-active .header {
  margin-top: -80px;
  opacity: 0;
}

.page-enter .content {
  opacity: 0;
  transition: opacity .8s ease-in-out .8s;
}

.page-enter-active .content {
  opacity: 1;
}

.page-leave .content {
  opacity: 1;
  transition: opacity .8s ease-in-out;
}

.page-leave-active .content {
  opacity: 0;
}

我知道可以使用transitionAppear={true}来动画化初始挂载 - 但这并不能解决新组件在旧组件过渡之前被挂载的问题。
这是我苦苦思索了几天,却找不到解决方案的问题。
一些可供测试的代码: https://jsfiddle.net/gonsfx/xva2g6oo/

1
你解决了吗?我也卡在这个问题上了。 - bhootjb
2个回答

1

我已经为页面添加了一个状态来保存 opacity(用于动画),并在组件挂载时将其设置为 1(初始值为 0),并带有一定的延迟。因此,我为每个页面添加了两个函数。

componentDidMount() {
    setTimeout(() => {
        this.setState({
            opacity: 1
        });
    }, 20);
}

getStyle() {
    return { opacity: this.state.opacity };
}

然后我添加了一个构造函数来进行初始设置....
constructor(props) {
    super(props);
    this.state = { opacity: 0 };
    this.getStyle = this.getStyle.bind(this);
    this.componentDidMount = this.componentDidMount.bind(this);
}

这里是一个演示。

组件将立即出现在页面上,所以我认为不可能进行淡出动画(至少我没有找到解决方案)。


这并没有在显示新页面前淡出旧页面。而且,它完全绕开了CSSTransitionGroup。谢谢你的努力。 - Codepunkt

0

好的。经过翻阅大量最新和旧的文档,我成功解决了这个问题。这里是解决方案

基本上,react-router 只关注父容器的动画。但这意味着使用 ReactTransitionGroup,我们可以在即将退出的组件中钩入 componentWillLeave 方法,从而使单个子元素进行操作。子组件也可以使用 ReactCSSTransitionGroup 以便于进行 appear 转换。

因此,您可能无法仅使用 CSSTransitionGroup,而是需要混合使用 CSSTransitionGroupTransitionGroup

这样,通过 hook 自动更改页面将使子元素进行动画处理,而进入页面则使用 CSSTransitionGroup 进行单个动画。

解决方案中的 setTimeout 可能看起来像一个 hack,但目前这就是我所能做的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接