React為動畫提供一個`ReactTransitonGroup`插件組件作為一個底層的API,一個`ReactCSSTransitionGroup`來簡單地實現基本的CSS動畫和過渡。
## 高級API:`ReactCSSTransitionGroup`
`ReactCSSTransitionGroup`是基于`ReactTransitionGroup`的,在React組件進入或者離開DOM的時候,它是一種簡單地執行CSS過渡和動畫的方式。這個的靈感來自于優秀的[ng-animate](http://www.nganimate.org/)庫。
### 快速開始
`ReactCSSTransitionGroup`是`ReactTransitions`的接口。這是一個簡單的元素,包含了所有你對其動畫感興趣的組件。這里是一個例子,例子中我們讓列表項淡入淡出。
~~~
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
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;
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">
{items}
</ReactCSSTransitionGroup>
</div>
);
}
});
~~~
> 注意:
>
> 你必須為`ReactCSSTransitionGroup`的所有子級提供[`鍵`屬性](http://reactjs.cn/react/docs/multiple-components.html#dynamic-children),即使只渲染一項。這就是React確定哪一個子級插入了,移除了,或者停留在那里。
在這個組件當中,當一個新的項被添加到`ReactCSSTransitionGroup`,它將會被添加`example-enter`類,然后在下一時刻被添加`example-enter-active`?CSS類。這是一個基于`transitionName`?prop的約定。
你可以使用這些類來觸發一個CSS動畫或者過渡。例如,嘗試添加這段CSS代碼,然后插入一個新的列表項:
~~~
.example-enter {
opacity: 0.01;
transition: opacity .5s ease-in;
}
.example-enter.example-enter-active {
opacity: 1;
}
~~~
你將注意到,當你嘗試移除一項的時候,`ReactCSSTransitionGroup`保持該項在DOM里。如果你正使用一個帶有插件的未壓縮的React構建版本,你將會看到一條警告:React期待一次動畫或者過渡發生。那是因為`ReactCSSTransitionGroup`保持你的DOM元素一直在頁面上,直到動畫完成。嘗試添加這段CSS代碼:
~~~
.example-leave {
opacity: 1;
transition: opacity .5s ease-in;
}
.example-leave.example-leave-active {
opacity: 0.01;
}
~~~
### 一組動畫必須要掛載了才能生效
為了能夠給它的子級應用過渡效果,`ReactCSSTransitionGroup`必須已經掛載到了DOM。下面的例子不會生效,因為`ReactCSSTransitionGroup`被掛載到新項,而不是新項被掛載到`ReactCSSTransitionGroup`里。將這個與上面的[快速開始](http://reactjs.cn/react/docs/animation.html#getting-started)部分比較一下,看看有什么差異。
~~~
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 = React.addons.CSSTransitionGroup;
var ImageCarousel = React.createClass({
propTypes: {
imageSrc: React.PropTypes.string.isRequired
},
render: function() {
return (
<div>
<ReactCSSTransitionGroup transitionName="carousel">
<img src={this.props.imageSrc} key={this.props.imageSrc} />
</ReactCSSTransitionGroup>
</div>
);
}
});
~~~
### 禁用動畫
如果你想,你可以禁用`入場`或者`出場`動畫。例如,有些時候,你可能想要一個`入場`動畫,不要`出場`動畫,但是`ReactCSSTransitionGroup`會在移除DOM節點之前等待一個動畫完成。你可以給`ReactCSSTransitionGroup`添加`transitionEnter={false}`或者`transitionLeave={false}`?props來禁用這些動畫。
> 注意:
>
> 當使用`ReactCSSTransitionGroup`的時候,沒有辦法通知你在過渡效果結束或者在執行動畫的時候做一些復雜的運算。如果你想要更多細粒度的控制,你可以使用底層的`ReactTransitionGroup`?API,該API提供了你自定義過渡效果所需要的函數。
## 底層的API:`ReactTransitionGroup`
`ReactTransitionGroup`是動畫的基礎。它可以通過`React.addons.TransitionGroup`得到。當子級被添加或者從其中移除(就像上面的例子)的時候,特殊的生命周期函數就會在它們上面被調用。
### `componentWillEnter(callback)`
在組件被添加到已有的`TransitionGroup`中的時候,該函數和`componentDidMount()`被同時調用。這將會阻塞其它動畫觸發,直到`callback`被調用。該函數不會在`TransitionGroup`初始化渲染的時候調用。
### `componentDidEnter()`
該函數在傳給`componentWillEnter`的`callback`函數被調用之后調用。
### `componentWillLeave(callback)`
該函數在子級從`ReactTransitionGroup`中移除的時候調用。雖然子級被移除了,`ReactTransitionGroup`將會使它繼續在DOM中,直到`callback`被調用。
### `componentDidLeave()`
該函數在`willLeave`?`callback`被調用的時候調用(與`componentWillUnmount`是同一時間)。
### 渲染一個不同的組件
默認情況下`ReactTransitionGroup`渲染一個`span`。你可以通過提供一個`component`?prop來改變這種行為。例如,以下是你將如何渲染一個``:
~~~
<ReactTransitionGroup component="ul">
...
</ReactTransitionGroup>
~~~
每一個React能渲染的DOM組件都是可用的。但是,`組件`并不需要是一個DOM組件。它可以是任何你想要的React組件;甚至是你自己已經寫好的!
> 注意:
>
> v0.12之前,當使用DOM組件的時候,`組件`?prop需要是一個指向`React.DOM.*`的引用。既然組件簡單地傳遞到了`React.createElement`,它必須是一個字符串。組裝的組件必須傳遞構造函數。
任何額外的、用戶定義的屬性將會成為已渲染的組件的屬性。例如,以下是你將如何渲染一個帶有css類的``:
~~~
<ReactTransitionGroup component="ul" className="animated-list">
...
</ReactTransitionGroup>
~~~