Edit on GitHub

动画

React 提供了一个 ReactTransitionGroup 插件作为动画的底层API,和一个 ReactCSSTransitionGroup 用于轻松实现基础的CSS动画和过渡。

高级 API: ReactCSSTransitionGroup #

ReactCSSTransitionGroup 基于 ReactTransitionGroup 是一个当React组件进入或离开DOM时,执行CSS动画和过渡的简单方法。它的灵感来自于杰出的 ng-animate 库。

入门指南 #

ReactCSSTransitionGroupReactTransitions 的接口。这是一个简单的元素,包裹了所有你感兴趣的动画组件。这里是一个淡入和淡出列表项目的例子。

var ReactCSSTransitionGroup = require('react-addons-css-transition-group');

var TodoList = React.createClass({
  getInitialState: function() {
    return {items: ['hello', 'world', 'click', 'me']};
  },
  handleAdd: function() {
    var newItems =
      this.state.items.concat([prompt('Enter some text')]);
    this.setState({items: newItems});
  },
  handleRemove: function(i) {
    var newItems = this.state.items.slice();
    newItems.splice(i, 1);
    this.setState({items: newItems});
  },
  render: function() {
    var items = this.state.items.map(function(item, i) {
      return (
        <div key={item} onClick={this.handleRemove.bind(this, i)}>
          {item}
        </div>
      );
    }.bind(this));
    return (
      <div>
        <button onClick={this.handleAdd}>Add Item</button>
        <ReactCSSTransitionGroup 
          transitionName="example" 
          transitionEnterTimeout={500} 
          transitionLeaveTimeout={300}>
          {items}
        </ReactCSSTransitionGroup>
      </div>
    );
  }
});

注意:

你必须为ReactCSSTransitionGroup的所有子级提供 key 属性,即使只渲染一个项目。这就是React将决定哪一个子级进入,离开,或者停留

在这个组件,当一个新的项目被添加到 ReactCSSTransitionGroup ,他将得到example-enter CSS类 并且在下一刻example-enter-active CSS类被添加。这是一个基于transitionName prop 的约定。

你可以使用这些类来触发CSS动画和过渡。比如,尝试添加这个CSS和添加一个新的列表项:

.example-enter {
  opacity: 0.01;
}

.example-enter.example-enter-active {
  opacity: 1;
  transition: opacity 500ms ease-in;
}

.example-leave {
  opacity: 1;
}

.example-leave.example-leave-active {
  opacity: 0.01;
  transition: opacity 300ms ease-in;
}

你会注意到动画持续时间需要被同时在CSS和渲染方法里被指定;这告诉React什么时候从元素中移除动画类,并且 -- 如果它正在离开 -- 何时从DOM移除元素。

让初始化挂载动画 #

ReactCSSTransitionGroup 提供了可选的prop transitionAppear,来为在组件初始挂载添加一个额外的过渡阶段。 通常在初始化挂载时没有过渡阶段因为transitionAppear 的默认值为false。下面是一个传递transitionAppear 为值true的例子。

  render: function() {
    return (
      <ReactCSSTransitionGroup 
        transitionName="example" 
        transitionAppear={true} 
        transitionAppearTimeout={500}>
        <h1>Fading at Initial Mount</h1>
      </ReactCSSTransitionGroup>
    );
  }

在初始化挂载时 ReactCSSTransitionGroup 将获得example-appear CSS类 并且example-appear-active CSS 类在下一刻被添加。

.example-appear {
  opacity: 0.01;
}

.example-appear.example-appear-active {
  opacity: 1;
  transition: opacity .5s ease-in;
}

在初始化挂载,所有的 ReactCSSTransitionGroup 子级将会 appear 但不 enter。然而,所有后来添加到已存在的 ReactCSSTransitionGroup 的子级将 enter 但不 appear

注意:

prop transitionAppear 在版本 0.13 被添加到 ReactCSSTransitionGroup。为了保持向后兼容,默认值被设置为 false

制定类 #

可以为你的每一步过渡使用制定类名字。代理传递一个字符串到transitionName,你可以传递一个含有enter 或者leave 类名的对象,或者一个含有 enter, enter-active, leave-active, 和 leave 类名的对象。只要提供了enter 和 leave 的类,enter-active 和 leave-active 类会被决定为后缀'-active' 到类名的尾部。这里是两个使用制定类的例子:

  ...
  <ReactCSSTransitionGroup
    transitionName={ {
      enter: 'enter',
      enterActive: 'enterActive',
      leave: 'leave',
      leaveActive: 'leaveActive',
      appear: 'appear',
      appearActive: 'appearActive'
    } }>
    {item}
  </ReactCSSTransitionGroup>

  <ReactCSSTransitionGroup
    transitionName={ {
      enter: 'enter',
      leave: 'leave',
      appear: 'appear'
    } }>
    {item2}
  </ReactCSSTransitionGroup>
  ...

动画组必须挂载才工作 #

为了使过渡效果应用到子级上,ReactCSSTransitionGroup必须已经挂载到了DOM或者 prop transitionAppear 必须被设置为 true。下面的例子不会工作,因为 ReactCSSTransitionGroup 随同新项目被挂载,而不是新项目在它内部被挂载。将这与上面的入门指南部分比较一下,看看不同。

  render: function() {
    var items = this.state.items.map(function(item, i) {
      return (
        <div key={item} onClick={this.handleRemove.bind(this, i)}>
          <ReactCSSTransitionGroup transitionName="example">
            {item}
          </ReactCSSTransitionGroup>
        </div>
      );
    }, this);
    return (
      <div>
        <button onClick={this.handleAdd}>Add Item</button>
        {items}
      </div>
    );
  }

动画一个或者零个项目 Animating One or Zero Items #

在上面的例子中,我们渲染了一系列的项目到ReactCSSTransitionGroup里。然而 ReactCSSTransitionGroup 的子级同样可以是一个或零个项目。这使它能够动画化单个元素的进入和离开。同样,你可以动画化一个新的元素替换当前元素。例如,我们可以像这样实现一个简单的图片轮播器:

var ReactCSSTransitionGroup = require('react-addons-css-transition-group');

var ImageCarousel = React.createClass({
  propTypes: {
    imageSrc: React.PropTypes.string.isRequired
  },
  render: function() {
    return (
      <div>
        <ReactCSSTransitionGroup 
          transitionName="carousel" 
          transitionEnterTimeout={300} 
          transitionLeaveTimeout={300}>
          <img src={this.props.imageSrc} key={this.props.imageSrc} />
        </ReactCSSTransitionGroup>
      </div>
    );
  }
});

禁用动画 #

如果你想,你可以禁用 enter 或者 leave 动画。例如,有时你可能想要一个 enter 动画,不要 leave 动画,但是 ReactCSSTransitionGroup 会在移除你的DOM节点之前等待一个动画完成。你可以添加transitionEnter={false} 或者 transitionLeave={false} props 到 ReactCSSTransitionGroup 来禁用这些动画。

注意:

当使用 ReactCSSTransitionGroup 时,没有办法通知你的组件何时过渡效果结束或者在动画时执行任何复杂的逻辑运算。如果你想要更多细粒度的控制,你可以使用底层的 ReactTransitionGroup API,它提供了你自定义过渡效果所需要的挂钩。

底层 API: ReactTransitionGroup #

ReactTransitionGroup是动画的基础。它通过 require('react-addons-transition-group') 访问。当子级被声明式的从其中添加或移除(就像上面的例子)时,特殊的生命周期挂钩会在它们上面被调用。

componentWillAppear(callback) #

对于被初始化挂载到 TransitionGroup 的组件,它和 componentDidMount() 在相同时间被调用 。它将会阻塞其它动画发生,直到callback被调用。它只会在 TransitionGroup 初始化渲染时被调用。

componentDidAppear() #

在 传给componentWillAppear回调 函数被调用后调用。

componentWillEnter(callback) #

对于被添加到已存在的 TransitionGroup 的组件,它和 componentDidMount() 在相同时间被调用 。它将会阻塞其它动画发生,直到callback被调用。它不会在 TransitionGroup 初始化渲染时被调用。

componentDidEnter() #

在传给 componentWillEnter回调函数被调用之后调用。

componentWillLeave(callback) #

在子级从 ReactTransitionGroup 中移除时调用。虽然子级被移除了,ReactTransitionGroup 将会保持它在DOM中,直到callback被调用。

componentDidLeave() #

willLeave callback 被调用的时候调用(与 componentWillUnmount 同一时间)。

渲染一个不同的组件 #

默认情况下 ReactTransitionGroup 渲染为一个 span。你可以通过提供一个 component prop 来改变这种行为。例如,下面是你将如何渲染一个<ul>

<ReactTransitionGroup component="ul">
  ...
</ReactTransitionGroup>

每一个React能渲染的DOM组件都是可用的。然而,组件不需要是一个DOM组件。它可以是任何你想要的React组件;甚至是你自己已经写好的!只要写 component={List} 你的组件会收到 this.props.children

任何额外的、用户定义的属性将会成为已渲染的组件的属性。例如,以下是你将如何渲染一个带有css类的 <ul>

<ReactTransitionGroup component="ul" className="animated-list">
  ...
</ReactTransitionGroup>