React为动画提供一个ReactTransitonGroup插件组件作为一个底层的API,一个ReactCSSTransitionGroup来简单地实现基本的CSS动画和过渡。
ReactCSSTransitionGroup #ReactCSSTransitionGroup是基于ReactTransitionGroup的,在React组件进入或者离开DOM的时候,它是一种简单地执行CSS过渡和动画的方式。这个的灵感来自于优秀的ng-animate库。
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的所有子级提供键属性,即使只渲染一项。这就是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里。将这个与上面的快速开始部分比较一下,看看有什么差异。
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>
);
}
虽然在上面的例子中,我们渲染了一个项目列表到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的时候,没有办法通知你在过渡效果结束或者在执行动画的时候做一些复杂的运算。如果你想要更多细粒度的控制,你可以使用底层的ReactTransitionGroupAPI,该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来改变这种行为。例如,以下是你将如何渲染一个<ul>:
<ReactTransitionGroup component="ul">
...
</ReactTransitionGroup>
每一个React能渲染的DOM组件都是可用的。但是,组件并不需要是一个DOM组件。它可以是任何你想要的React组件;甚至是你自己已经写好的!
注意:
v0.12之前,当使用DOM组件的时候,
组件prop需要是一个指向React.DOM.*的引用。既然组件简单地传递到了React.createElement,它必须是一个字符串。组装的组件必须传递构造函数。
任何额外的、用户定义的属性将会成为已渲染的组件的属性。例如,以下是你将如何渲染一个带有css类的<ul>:
<ReactTransitionGroup component="ul" className="animated-list">
...
</ReactTransitionGroup>