React 动画 Animation

文章源自: https://facebook.github.io/react/docs/animation.htmlcss

ReactCSSTransitionGroup 基于 ReactTransitionGroup ,当一个React组件enter或者leave时能够方便的用来执行CSS transitions和animations。html

导入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属性,即便只渲染一个elementreact

在这个组件中,当添加一个元素到 ReactCSSTransitionGroup 中时,这个元素将会自动添加上 example-enter 和 example-enter-active 样式。添加上的样式基于 transitionName 这个属性来设置。咱们须要作的就是定义example-xxx等样式;git

.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分别表示动画开始和动画结束时的样式定义;github

动画时间在css样式表中和render方法中,都必须指定,时间用来告诉React何时去移除animation样式以及何时从DOM中移除元素。web

初始加载动画

ReactCSSTransitionGroup 提供了可选的属性 transitionAppear ,用来指定组件初始加载时的动画,该属性默认值是false,因此在组件加载的时候默认是没有动画的; npm

return (
     <CSSTransitionGroup
            className="animateExample"
            transitionAppear={true}
            transitionAppearTimeout={1500}
            transitionEnterTimeout={1500}
            transitionLeaveTimeout={1500}
            transitionName="example">
             {children}
     </CSSTransitionGroup>
);

修改组件的render方法,而且在css中定义example-appear, example-appear-active样式;api

.example-appear {
    opacity: 0.01;
    margin-left: 128px;
}

.example-appear.example-appear-active {
    opacity: 1;
    margin-left: 0;
}

这样在组件初始加载的时候,也会有动画了!app

组件第一次加载的时候,执行的动画是appear,以后再有element动态添加到CSSTransitionGroup,将会执行enter动画,而不会是appear动画;dom

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