文章源自: https://facebook.github.io/react/docs/animation.html
ReactCSSTransitionGroup
基于 ReactTransitionGroup
,当一个React组件enter或者leave时可以方便的用来执行CSS transitions和animations。
导入ReactCSSTransitionGroup
import ReactCSSTransitionGroup from 'react-addons-css-transition-group' // ES6 var ReactCSSTransitionGroup = require('react-addons-css-transition-group') // ES5 with npm var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup; // ES5 with react-with-addons.js
定义组件
var React = require('react'); var ReactDOM = require('react-dom'); var CSSTransitionGroup = require('react-addons-css-transition-group'); var INTERVAL = 2000; var AnimateDemo = React.createClass({ getInitialState: function() { return {current: 0}; }, componentDidMount: function() { this.interval = setInterval(this.tick, INTERVAL); }, componentWillUnmount: function() { clearInterval(this.interval); }, tick: function() { this.setState({current: this.state.current + 1}); }, render: function() { var children = []; var pos = 0; var colors = ['red', 'gray', 'blue']; for (var i = this.state.current; i < this.state.current + colors.length; i++) { var style = { left: pos * 128, background: colors[i % colors.length] }; pos++; children.push(<div key={i} className="animateItem" style={style}>{i}</div>); } return ( <CSSTransitionGroup className="animateExample" transitionEnterTimeout={1500} transitionLeaveTimeout={1500} transitionName="example"> {children} </CSSTransitionGroup> ); } });
注意: 必须给 ReactCSSTransitionGroup 中的每一个child设置一个key属性,即使只渲染一个element
!
在这个组件中,当添加一个元素到 ReactCSSTransitionGroup 中时,这个元素将会自动添加上
example-enter
和 example-enter-active
样式。添加上的样式基于 transitionName 这个属性来设置。
我们需要做的就是定义example-xxx等样式;
.example-enter, .example-leave { -webkit-transition: all 2s; transition: all 2s; } .example-enter { /* begin **/ opacity: 0.01; margin-left: 128px; } .example-enter.example-enter-active { /* finish **/ opacity: 1; margin-left: 0; } .example-leave { opacity: 1; margin-left: 0; } .example-leave.example-leave-active { opacity: 0.01; margin-left: -128px; } .animateExample { display: block; height: 128px; position: relative; width: 384px; } .animateItem { color: white; font-size: 36px; font-weight: bold; height: 128px; line-height: 128px; position: absolute; text-align: center; -webkit-transition: all 1s; /* TODO: make this a move animation */ transition: all 1s; /* TODO: make this a move animation */ width: 128px; }
example-enter和example-enter-active分别表示动画开始和动画结束时的样式定义;
动画时间在css样式表中和render方法中,都必须指定,时间用来告诉React什么时候去移除animation样式以及什么时候从DOM中移除元素。
初始加载动画
ReactCSSTransitionGroup 提供了可选的属性 transitionAppear ,用来指定组件初始加载时的动画,该属性默认值是false,所以在组件加载的时候默认是没有动画的;
return ( <CSSTransitionGroup className="animateExample" transitionAppear={true} transitionAppearTimeout={1500} transitionEnterTimeout={1500} transitionLeaveTimeout={1500} transitionName="example"> {children} </CSSTransitionGroup> );
修改组件的render方法,并且在css中定义example-appear, example-appear-active样式;
.example-appear { opacity: 0.01; margin-left: 128px; } .example-appear.example-appear-active { opacity: 1; margin-left: 0; }
这样在组件初始加载的时候,也会有动画了!
组件第一次加载的时候,执行的动画是appear,之后再有element动态添加到CSSTransitionGroup,将会执行enter动画,而不会是appear动画;
transitionEnter和transitionLeave默认值是true,所以如果不把它们指定为false的话得指定transitionEnterTimeout和transitionLeaveTimeout。
自定义Classes
除了通过transitionName指定样式,还可以指定每一步的动画样式,其中,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> // ...
Animating One or Zero Items
上面所实现的动画,都是整个Group中的元素都将被设置动画,实际上还可以指定只需要某一/零个元素执行动画;
import ReactCSSTransitionGroup from 'react-addons-css-transition-group'; function ImageCarousel(props) { return ( <div> <ReactCSSTransitionGroup transitionName="carousel" transitionEnterTimeout={300} transitionLeaveTimeout={300}> <img src={props.imageSrc} key={props.imageSrc} /> </ReactCSSTransitionGroup> </div> ); }
Animation Group Must Be Mounted To Work
为了组child添加动画属性,ReactCSSTransitionGroup
必须已经被加载到DOM中,或者将 transitionAppear
设置成true。
render() { const items = this.state.items.map((item, i) => ( <div key={item} onClick={() => this.handleRemove(i)}> <ReactCSSTransitionGroup transitionName="example"> {item} </ReactCSSTransitionGroup> </div> )); return ( <div> <button onClick={this.handleAdd}>Add Item</button> {items} </div> ); }
上面这个例子将不会起作用,因为ReactCSSTransitionGroup
被加载到新的div中,而不是已经加载好的元素当中,且没有设置transitionAppear。
Disabling Animations
还可以禁止掉enter或者是leave动画,比如希望有enter动画而不想要leave动画,但是ReactCSSTransitionGroup需要等待动画完成后才从dom中remove元素,此时可以通过设置transitionEnter={false}或者transitionLeave={false}来禁止相应的动画;
在ReactCSSTransitionGroup中,没有动画完成的监听,所以如果想要获取到动画的执行进度并且添加其它操作是不可行的,如果确实有需要,可以使用ReactTransitionGroup;