第10章 动画
动画可以让用户体验变得更加流畅自然,而React的TransitionGroup插件配合CSS3可以让我们在项目中整合动画效果的变得易如反掌。
通常情况下,浏览器中的动画都拥有一套极其命令式的API,你需要选择一个元素并主动移动它或者改变它的样式,已实现动画效果。这种渲染方式显得格格不入,因此React选择了一种偏声明式的方法实现动画。
CSS渐变组(CSS Transition Group)会在何时的渲染及重渲染时间点有策略地添加和移动元素的class,以此来简化将CSS动画应用于渐变的过程,这意味着唯一需要你完成的任务就是给这些class写明合适的样式。
间隔渲染以牺牲性能为代价提供饿了更多的扩展性和可控性。这种方法需要更多次的渲染,但同时也允许你为CSS之外的内容,(比如滚动条位置及Canvas绘画)添加动画。
CSS渐变组:
<ReactCSSTransitionGrouptransitionName='question'>
{questions}
</ReactCSSTransitionGroup>
ReactCSSTransitionGroup 是一款插件,它在文件最顶部通过var ReactCSSTransitionGroup =React.addons.ReactCSSTransitionGroup;
语句引入。 它会自动在合适的时候处理组件重渲染,同时根据当前的渐变状态调整渐变组的class以便实现组件样式的改变。
给渐变的class添加样式
为元素添加transitionName ='question'意味着给它添加饿了4个class:question-enter、question-enter-active、question-leave及question-leave-active。当子组件进入或者退出ReactCSSTranstionGroup时,CSSTransitionGroup插件会自动添加或移除这些Class。
以下是问卷编辑器中使用到的渐变样式:
survey-editor.question-enter{ transform:scale(1.2); transition:transform 0.2s cubic-bezier(.97,.84,.5,1.21); } .survey-editor.question-enter-active{ transform:scale(1); } .survey-editor.question-leave{ transform:translateY(0); opacity:0; transition:opacity 1.25,transgorm 1scubic-bezier(.52,-0.25,.52,.95); } .survey-editor.question-leave-active{ opacity:0; transform:translateY(-100%); }
渐变生命周期
question-enter与question-enter-active的区别在于,question-enter这个class是组件被添加到渐变组后即刻添加上的,而question-enter-active则是在下一轮渲染时添加的,这样设计让你能轻松的定义渐变开始时候的样式,结束时候的样式以及如何进行渐变。
例如:当问卷调查器重的问题被添加到列表的时候他们首先用scale(1.2)进行发大,然后渐变到正常的scale(1)状态,总共花了0.2秒,这就创造出了一种你看到的跳出来的效果。默认情况下,渐变组同事开启了进入和退出的动画,你可以通过给组件添加transitionEnter={false}或tranitionLeave={false}属性来禁用其中一个或全部禁用,除了可以控制选择哪些动画外,我们还能根据一个可配置 的值在特定的情况下禁用动画,像是这样:
<ReactCSSTransitionGrouptransitionName='question' transitionEnter={this.props.enableAnimations} transitionLeave={this.props.enableAnimations}>
{questions}
</ReactCSSTransitionGroup>
使用渐变组的隐患
使用渐变组主要有两个重要的隐患需要注意
首先,渐变组会延迟子组件的移除直到动画完成,这意味着如果你把一个列表的组件包裹进一个ReactCSSTransitionGroup中,却没有trasitionName属性指定的class明确任何CSS,这些组件将无法被移除——甚至当你尝试不再渲染它们时也不可以。
其次渐变组每一个子组件都必须设置一个独一无二的key属性,渐变组使用这个属性来判断组件究竟是进入还是退出,因为如果没有设置key属性动画可能无法执行,同时组件会变得无法移除。
注意,即使渐变组只有一个子元素,它也需要设置一个key属性。
间隔渲染
使用CSS3动画能够获得巨大的性能提升并拥有简洁的代码,但他们并不总是解决问题的正确工具,有些时候,你必须为比较老,不支持CSS3的浏览器做兼容,还有些时候你想为CSS属性之外的东西添加动画,比如滚动条位置和Canvas绘画,这些情况下,间隔渲染能够满足我们的要求,但是相比CSS3动画来说,它会带来一定的性能损耗。
间隔渲染最基本的思想就是周期性的触发组件状态更新,以明确当前处于整个动画时间中的什么阶段。通过在组件的render方法中加入这个状态值,组件能够在每次状态更新触发的重渲染中正确的表示当前的动画阶段。
因为这种方法设计多次重渲染,所以通常最好和requestAnimationFrame一起使用以避免不必要的渲染,不过在requestAnimationFrame不被支持或不可用的情况下,降级到不那么智能的setTimeout就是唯一的选择了。
使用requestAnimationFrame实现间隔渲染
假设你希望使用间隔渲染将一个div从屏幕的一边移动到另一边,可以通过给他添加position:absolute并随着时间变化不停的更新left属性或者top属性来实现,根据消耗时间内的变化总量,用requestAnimationFrame来实现这个动画应该可以得出一个流畅的动画。
示例:page90
使用setTimeout实现间隔渲染
尽管requestAnimatingFrame总体上能够以最小的性能损耗实现最流畅的动画,但它在比较老的浏览器上无法使用的,而且它被调用的次数可能比你想象的更频繁(也更加无法预测)。这些情况下你可以使用setTimout。
示例:page91