---
id: animation-zh-CN
title: 动画
permalink: animation-zh-CN.html
prev: addons-zh-CN.html
next: two-way-binding-helpers-zh-CN.html
---

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

## 高级 API: `ReactCSSTransitionGroup`

`ReactCSSTransitionGroup` 基于 `ReactTransitionGroup` 是一个当React组件进入或离开DOM时，执行CSS动画和过渡的简单方法。它的灵感来自于杰出的 [ng-animate](http://www.nganimate.org/) 库。

### 入门指南

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

```javascript{28-30}
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/docs/multiple-components.html#dynamic-children)，即使只渲染一个项目。这就是React将决定哪一个子级进入，离开，或者停留

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

你可以使用这些类来触发CSS动画和过渡。比如，尝试添加这个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`的例子。

```javascript{3-5}
  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 类在下一刻被添加。

```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' 到类名的尾部。这里是两个使用制定类的例子：

```javascript
  ...
  <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` 随同新项目被挂载，而不是新项目在它内部被挂载。将这与上面的[入门指南](#入门指南)部分比较一下，看看不同。

```javascript{12-15}
  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` 的子级同样可以是一个或零个项目。这使它能够动画化单个元素的进入和离开。同样，你可以动画化一个新的元素替换当前元素。例如，我们可以像这样实现一个简单的图片轮播器：

```javascript{10-12}
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>`：

```javascript{1}
<ReactTransitionGroup component="ul">
  ...
</ReactTransitionGroup>
```

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


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

```javascript{1}
<ReactTransitionGroup component="ul" className="animated-list">
  ...
</ReactTransitionGroup>
```
