此文章是翻译Animation这篇React(版本v15.4.0)官方文档。
Animation Add-Ons
ReactTransitionGroup add-on component 是低级的动画API,ReactCSSTransitionGroup 是一个简单显示基本CSS 动画和变形的add-on component。
High-level API: ReactCSSTransitionGroup
ReactCSSTransitionGroup 是一个基于 ReactTransitionGroup 的高级API并且当一个React component 进入或离开DOM 时很容易执行CSS 变形和动画。它的灵感来自优秀的ng-animate 库。
Importing
1 | import ReactCSSTranstionGroup from 'react-addons-css-transition-group' // ES6 |
1 | class TodoList extends Component { |
Note:
你必须为ReactCSSTransitionGroup的所有子节点提供thekeyattribute,即使值渲染单独的一个条目。这是React 如何决定那一个孩子已经进入、离开或停留。
在component 中,当一个条目被添加到ReactCSSTransitionGroup ,它将会获得example-enter 这个CSS 类,而example-enter-active 这个CSS 类将会在下一次点击时被加入。这是一个基于transitionName prop 的规则。
你可以使用下面这些类去触发一个CSS 动画或变形。例如,尝试添这个CSS 并添加一个新的条目:
1 | .example-enter { |
你已经注意到动画持续时间需要在CSS 和渲染方法中这两个地方配置;这告诉React 什么时候从element 中移除动画类(animation class)– 如果它正在离开–什么时候从DOM 中移除element。
Animate Inital Mounting
ReactCSSTransitionGroup 提供一个可选的属性transionAppear,添加一个在首次加载component 时的额外变形阶段。在首次加载时通常没有变形阶段因为transitionAppear 默认值是false。下面这个例子传入的transitionAppear 的值为true。
1 | render() { |
在首次加载ReactCSSTransitionGroup 期间将会得到example-appear 这个CSS 类,在下次点击时example-appear-active CSS 类被添加。
1 | .example-appear { |
在首次加载是,ReactCSSTransitionGroup 的所有的子节点会得到appear 而不是enter。然后,之后所有的子节点都会添加到一个已经存在的ReactCSSTransitionGroup 中是enter 而不是appear。
Note:
在0.13版本中transitionAppear被添加到ReactCSSTransitionGroup。为了保持向后兼容,默认值被设置为false。
然后,transitionEnter和transitionLeave的默认值是true因此默认你必须配置transitionEnterTimeout和transitionLeaveTimeout。如果不需要进入和离开动画,传transitionEnter={false}或者transitionLeave={false}。
Custom Classes
有可能会使用自定义类名为你的变形中的每一个步骤。替代传入一个字符串到变形名称(transitionName),你可以传入一个包含enter 和leave 类名的对象,或者这个对象包含enter,enter-active,leave-active和leave 类名。如果只有进入和离开类被提供,enter-active 和leave-active 类名将同追加-active 到类名之后来决定。下面是两个使用自定义类的例子:
1 | // ... |
Animation Group Must Be Mounted To Work
为了将变形应用到孩子节点上,ReactCSSTransitionGroup 必须已经被加载到DOM 中或这transitionAppear 属性必须被设置为true。
下面这个例子将不会工作,因为ReactCSSTransitionGroup 正在随着新条目被加入,而不是这个新条目随着它被加载。对比这块和上面Getting Started 去查看不同。
1 | render() { |
Animating One or Zero Items
在上述例子中,我们渲染一个条目列表到ReactCSSTransitionGroup。然后,ReactCSSTransitionGroup 中的孩子可能会只有一个或零个条目。这会使得动画知道一个element 上进入或离开。同样的,你可以动画一个新element 替代当前的element。例如,我们可以实现像这样的一个图片旋转(image carousel ):
1 | import ReactCSSTransitionGroup from 'react-addons-css-transition-group'; |
Disabling Animations
你可以使动画的enter 或leave 失效如果你想要。例如,有时你可能想要一个enter 动画并且没有leave 动画,但是ReactCSSTransitionGroup 等待一个动画完成在移除你的DOM 节点之前。你可以添加transitionEnter={false}或者transitionLeave={false}属性到ReactCSSTransitionGroup使这些动画失效。
Note:
当使用ReactCSSTransitionGroup时,这没有为你的component 进行提醒到变形已经结束或者去执行任何更多的复杂逻辑在动画上。如果你想要更多粒度的(fine-grained)控制,你可以使用低级的ReactTransitionGroupAPI 去提供你需要自定义变形的钩子(hook)。
Low-level API: ReactTransitionGroup
Importing
1 | import ReactTransitionGroup from 'react-addons-transition-group' // ES6 |
ReactTransitionGroup 是基本的动画。当孩子节点被声明式的添加或移除(就像上例 ),配置在它上米昂的生命周期钩子(lifecycle hook)就会被调用。
- componentWillAppear()
- componentDidAppear()
- componentWillEnter()
- componentDidEnter()
- componentWillLeave()
- componentDidLeave()
Rendering a Different Component
ReactTransitionGroup 默认渲染成一个span。你可以通过提供一个component 属性来改变这个默认行为。例如,这里你将渲染成一个<ul>:
1 | <ReactTransitionGroup component="ul"> |
任何额外的、用户自定义的、属性都会称为已经渲染的component 上的属性。例如,这里你讲渲染一个带CSS 类型的<ul>:
1 | <ReactTransitionGroup component="ul" className="animated-list"> |
每一个React 可以渲染的DOM component 都是可供使用的。然而,component 必须要成为一个DOM component。它可以是你想要的任何React component;甚至每一个你都可以自己写!写一个component={List} ,你的component 将会收到this.props.children。
Rendering a Single Child
人们经常使用ReactTransitionGroup 去动画加载并且卸载单个子节点就像一个可拆卸的面板(collapsible panel)。通常ReactTransitionGroup 包裹所有的子节点在一个span 中(或者像上面描述的一个自定义component 中)。这是因为任何React comoennt 必须返回单个根element,ReactTranstionGroup 对这个规则也不例外。
然而如果你需要在ReactTransitionGroup 中渲染单个子节点,你可以完全避免把它包裹在一个<span> 或任何DOM component 中。为了实现它,创建一个自定义component 去直接渲染传入它的第一个子节点:
1 | function FirstChild(props) { |
现在你可以配置FirstChild 作为<ReactTransitionGroup> 的component 属性,避免在最终DOM 中有任何包裹。
1 | <ReactTransitionGroup component={FirstChild}> |
这只在你对单个孩子节点进入或出时工作,就像一个可拆卸的面板(collapsible panel)。当动画多个子节点或使用另一个子节点替换单个子节点,这种方式不会工作,就像一个一个图片轮播(an image carousel)。对于一个图片轮播,当当前图片正在动画出去是,另一个图片将要动画进入,导致<ReactTransitionGroup> 需要给它们一个通用的DOM 父节点。你不能为多个子节点避免包裹器,但是你可以按照上面的描述使用component 自定义包裹器。
Reference
componentWillAppear()
1 | componentWillAppear(callback) |
在一个TransitionGroup 中,初始化加载一个component 的componentDidMount() 方法的同时,这个方法被调用。它将阻止其它的动画发生直到callback 被调用。它只在TransitionGroup 的初次渲染中被调用。
componentDidAppear()
1 | componentDidAppear() |
当传入componentWillAppear 中的callback 函数被调用之后,这个方法才被调用。
componentWillEnter()
1 | componentWillEnter(callback) |
这个方法同已经被添加到TransitionGroup 中的component 的componentDidMount() 同时被调用。它将会阻止其它的动画反生,直到callback 被调用。它不会在TransitionGroup 的初次渲染时调用。
componentDidEnter()
1 | componentDidEnter() |
当传入componentWillEnter() 中的callback 函数被调用之后,这个方法才被调用。
componentWillLeave()
1 | componentWillLeave(callback) |
当孩子节点已经从ReactTransitionGroup 中被移除后才会被调用。虽然孩子节点已经被移除了,ReactTransitionGroup 仍然将其保留在DOM 中,直到callback 被调用
componentDidLeave()
1 | componentDidLeave() |
当willLeave callback 被调用时(和componentWillUnmount() 同时) ,它才被调用。