React Addons Animation
Animation
React 提供一个ReactTransitionGroup扩展组件作为动画的低级接口,和一个ReactCSSTransitionGroup用于轻松实现基于CSS的动画和转换效果。
高级别接口:ReactCSSTransitionGroup
ReactCSSTransitionGroup是基于ReactTransitionGroup的,它是一个当React组件进入或离开DOM的时候执行CSS转换与动画轻松的方式。它是受到了无与伦比的ng-animate库启发而创作的。
开始
ReactCSSTransitionGroup是ReactTransitions的接口。用一个简单的元素,将所有的具有动画效果的组件包裹起中。下面是个例子使列表元素淡入淡出。
1 var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup; 2 var MyComponent = React.createClass({ 3 getInitialState: function() { 4 return {items: ["hello", "world", "click", "me"]}; 5 }, 6 7 handleAdd: function() { 8 var newItems = this.state.items.concat([prompt("Enter some text")]); 9 this.setState({items: newItems}); 10 }, 11 12 handleRemove: function(i) { 13 var newItems = this.state.items; 14 newItems.splice(i, 1); 15 this.setState({items: newItems}); 16 }, 17 18 render: function() { 19 var items = this.state.items.map(function(item, i) { 20 return ( 21 <div key={item} onClick={this.handleRemove.bind(this, i)}> 22 {item} 23 </div> 24 ); 25 }.bind(this)); 26 27 return ( 28 <div> 29 <button onClick={this.handleAdd}>Add Item</button> 30 <ReactCSSTransitionGroup transitionName="example"> 31 {items} 32 </ReactCSSTransitionGroup> 33 </div> 34 ); 35 } 36 });
注意:你必须为ReactCSSTransitionGropu的子元素提供key属性,哪怕是只有一个元素。React依据它来决定哪个子元素进入,离开或停留。
在这个组件中,当一个新的元素添加到ReactCSSTransitionGroup后,它将会得到一个example-enter的CSS类,并在下一个时钟添加类名example-enter-active。这是一个基于transitionName属性的约定。
你可以使用这些类来触发CSS动作和转换。例如,试着添加下面的CSS并添加一个元素看看效果:
1 .example-enter { 2 opacity: .01; 3 transition: opacity .5s ease-in; 4 } 5 6 .example-enter.example-enter-active { 7 opacity: 1; 8 }
你会注意到等你删除一个ReactCSSTransitionGroup的子元素的时候,它依然还在。如果你使用的是未压缩的带有扩展的React版本,你会看到一条警告,React期待一个动画或转换发生。因为ReactCSSTransitionGroup会保持DOM元素存在于页面上直到动作完成。试着添加下面的CSS代码:
1 .example-leave { 2 opacity: 1; 3 transition: opacity .5s ease-in; 4 } 5 6 .example-leave.example-leave-active { 7 opacity: .01; 8 }
动画组必须是已经挂载的才能正常工作
为了给它的子元素应用转换,ReactCSSTransitionGroup必须已经存在于DOM中。下面的例子不会正常工作,因为ReactCSSTransitionGroup是随着新的元素添加而添加的,而不是新元素添加在其之内。对比一下上面的开始章节看看它们的不同之处。
1 render: function() { 2 var items = this.state.items.map(function(item, i) { 3 return ( 4 <div key={item} onClick={this.handleRemove.bind(this, i)}> 5 <ReactCSSTransitionGroup transitionName="example"> 6 {item} 7 </ReactCSSTransitionGroup> 8 </div> 9 ); 10 }.bind(this)); 11 12 return ( 13 <div> 14 <button onClick={this.handleAdd}>Add Item</button> 15 {items} 16 </div> 17 ); 18 }
为一个或另个元素添加动画效果
虽然在上面的实例中,我们渲染了一个列表到ReactCSSTransitionGroup中,ReactCSSTransitionGroup的子元素可以是一个或零个。这就有可能为一个单独的元素添加入出的动画。同样的,你可以通过替换当前的元素来为一个新元素添加动画,当前的动画结束后新元素的动画开始。例如,我们来实现一个简单的图片轮播效果:
var MyComponent = 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> ); } });
禁用动画
如果你需要可以禁用enter或leave动画。例如,有时你只需要enter的动画效果不需要leave的,但是ReactCSSTransitionGroup会在移除DOM节点之前等待动画完成。你可以添加transitionEenter={false}或transitionLeave={false}属性来禁用ReactCSSTransitionGroup的动画效果。
注意:当使用ReactCSSTransitionGroup的时候,你的组件没有办法在转换结束的时候收到通知或提示,或者无法执行复杂的动画逻辑。如果你需要更精细的动画控制,可以使用低级接口ReactTransitionGropu,它提供了自定义转换的钩子。
低级接口:ReactTransitionGropu
ReactTranstionGroup是动画的基础。可以通过React.addons.TransitionGroup访问。当子元素从其中声明添加或移除的时候(就像上面例子中的那样),指定的生命周期钩子会被调用。
componentWillEnter(callback)
在组件添加到一个已经存在的TransitonGroup时,它会和componentDidMount()一起被调用。他会阻塞其他动画的发生知道callback被调用。在初始化渲染一个TransitionGroup的时候,它不会被调用。
componentDidEnter()
它会在callback传递到被调用的componentWillEnter之后被调用。
componentWillLeave(callback)
它会在子元素从ReactTransitionGroup中移除时被调用。虽然子元素被移除了,ReactTransitionGroup会保留它在DOM中,直到callback被执行。
componentDidLeave()
当willLeave callback被调用是执行它(与componentWillUnmount同时执行)。
渲染不同的组件
默认的TractTransitionGroup渲染为一个span。你可以通过提供一个component属性类改变这种行为。例如,这里是如何渲染一个<ul>:
1 <ReactTransitionGroup component="url"> 2 ... 3 </ReactTransitionGroup>
任一DOM元素都可以被React有效的渲染使用。然而,component属性不是必须为DOM元素。它可以是任何React元素,甚至是你自己的实现的元素。
注意:在版本0.12之前,当使用DOM元素时,component属性必须要为React.DOM.*的引用。因为组件是被React.createElement来解析,它必须是一个字符串。复合组件必须为工厂方法解析。
其他的用户定义的属性将会变成渲染后的组件的属性呈现。例如,这里是如何为渲染的<ul>添加css类名:
1 <ReactTransitionGroup component="url" className="animated-list"> 2 ... 3 </ReactTransitionGroup>