不论是web应用仍是原生应用,也不管是PC端应用仍是移动端应用,动画都扮演了一个重要的角色。css
尽管动画并不会添加应用的实际动能,但一个好的动画,一个流畅且优雅,选择在恰当时机出现的动画,能为应用增色很多,能很好的引导用户进行下一步操做,让应用的场景切换更合理。一个小小的细节动画,就能几个层次的提高应用的用户体验。react
举个简单的例子,应用中最多见的页面间切换,若是缺乏切换动画,那就会是这个样子:git
很是生硬,页面的出现显得很是突兀。做为对比,咱们能够看下添加了动画的页面切换是什么样子的呢:github
增长了用户预期,也能较好的提示用户页面的层级关系。web
再举个弹窗的例子,先放两个对比图,左边是无动画的效果,右边是添加完动画的效果:spring
动画虽然没有添加什么实际可见的功能,可是经过对比,不难发现,动画的添加,让弹窗的出现显得平滑天然,让页面的场景替换有一个过程,减小突兀感,让用户体验感觉增色很多不是吗?segmentfault
固然有可能由于录制的问题,动画效果不是很明显,你可能有不一样的见解。
web应用的基本骨架是DOM,正是一个个的DOM节点,构建出web应用,换句话说,就是web应用呈现出来的样子是DOM决定的(固然这里把CSS样式,概括为了DOM的一部分)。因此动画的实现,从本质上来说,就是操做DOM:让DOM在不一样的时间节点,在不一样的位置、有不一样的大小、透明度、呈现不一样的背景色等,而且让这种变化连续起来,则构成了咱们能观察到的动画。框架
基于web动画实现的基本原理,在咱们直接操做DOM的时代,实现动画相对咱们来讲,很是直观——只要知道怎么操做DOM便可。好比须要实现一个黑色背景的div方块,1s内从离左边距100px的位置,移动到离左边距200px的位置,则咱们只须要每秒控制该div的left
值增长(200-100)/60px
便可实现一个匀速的动画效果。怎么样,很简单吧。函数
上述动画实现的方式,咱们称为JS动画。是由JS脚本逻辑,动态的改变DOM的CSS属性值。性能
CSS3中,添加了动画的实现的方案,因此web中第二种动画实现,被咱们称为CSS动画
。CSS动画,最主要的几个CSS属性是: transition,transform,animation,因为与本文的主题不是密切相关,此处就不作详细介绍,有兴趣能够自行搜索相关文章查阅。
这里的MV*模式咱们不展开说,特指React中动画的实现。React因为加入了虚拟DOM等诸多特性,而且其开发模式让开发者不须要或者不推荐直接接触到真实的DOM结构。因此其动画实现,与常规的开发方式下的动画实现,存在必定得差别。
动画的实现最终必定是落地到操做DOM,MV*模式的框架则是数据驱动DOM的展现。若是咱们由于动画实现的须要,对DOM的操做出现问题,势必会影响到应用的相关操做。咱们先不去深刻探讨怎么解决这个问题,先看看React官方和社区对这个问题是怎么解决的,让咱们能先给咱们的React应用添加上须要的动画。
由浅及深,咱们先学会怎么使用,再去了解内部的实现原理,从而根据应用自身需求,能实现自定义的动画,能实现更为复杂的交互动画等。
React的动画库中,比较经常使用的是react-addons-css-transition-group
、react-addons-transition-group
以及react-motion
。其中, react-addons-css-transition-group
是react-addons-transition-group
的High-Level API
库,react-addons-css-transtion-group
是基于react-addons-transition-group
的上层封装。目前react-addons-css-transition-group
和react-addons-transition-group
合并成一个库,叫react-transition-group
。
react-transition-group@v1.x
版本中的API, 基本保持与两个单独库的API形式一致,但@v2.x
版本中的API变化较大,并不能彻底切换,这个须要注意。本文的示例是以独立库,也就是类react-transtion-group@v1.x
API提供的。
另外一个经常使用的React动画库是react-motion
。该库拥有很是棒的特性,可以建立出很是细腻的动画,接着往下看,会介绍下基本的使用,而后参照其官方文档,相信能够实现出大多数你想要的动画的。
react-addons-css-transition-group
,通常称其export
的组件为ReactCSSTransitionGroup
,它提供一种声明的方式来定义CSS动画
。ReactCSSTransitionGroup
的子组件必须大于或等于1个,不能为空。
ReactCSSTranstionGroup
组件暴露的属性有:
span
,能够是React Element 。咱们以 todo-list 为例,看看ReactCSSTransitionGroup
怎么使用。因为篇幅限制,todo-list 相关的业务代码忽略,能够在这里查看完整代码。如下是动画部分代码:
index.js:
import React , { Component } from 'react' ; import ReactCSSTranstionGroup from 'react-addons-css-transition-group' ; export default class App extends Component{ ... , render(){ const { items } = this.state ; return ( <div> ... , <div className="list"> <ReactCSSTransitionGroup transitionName="example" transitionEnterTimeout={500} transitionLeaveTimeout={300} component="div" > { items.map((item)=>( <div key={item} className="item">{item}</div> )) } </ReactCSSTransitionGroup> </div> </div> ) } }
style.css:
.example-enter { opacity: 0.01; } .example-enter.example-enter-active { opacity: 1; transition: opacity 500ms ease-in; } .example-leave { opacity: 1; } .example-leave.example-leave-active { opacity: 0.01; transition: opacity 300ms ease-in; }
有两点须要注意:
key
,这样ReactCSSTrasntionGroup
才能正确的mounting
和unmounting
子组件。关于react-addons-css-transition-group
,知乎这篇文章CSS 动画及其在 React 中的应用有较为详细的介绍。
react-addons-transition-group
是react-addons-css-transition-group
的low-level
API,其提供动画执行中须要的各生命周期函数:
TransitionGroup
时执行而且只会执行一次。callback
执行后执行。TransitionGroup
时执行。callback
执行后执行。TransitionGroup
中移除时执行,Though the child has been removed, TransitionGroup will keep it in the DOM until callback is called.
callback
执行后执行。一般状况下与ComponentWillUnmount
的时机一致。那咱们看看,一样以 todo-list 为例, ReactTransitionGroup
须要怎么作呢?
index.js:
import React,{ Component } from 'react' ; import ReactTransitionGroup from 'react-addons-transition-group' ; class Item extends Component{ // 获取组件真实DOM getRef(ref){ this.ref=ref ; } componentWillEnter(callback){ this.ref.classList.add('example-enter') ; setTimeout(()=>{ callback() ; },500) ; } componentDidEnter(){ this.ref.classList.add('example-enter-active') ; } componentWillLeave(){ this.ref.classList.remove('example-enter','example-enter-active') ; this.ref.classList.add('example-leave-active','example-leave') ; setTimeout(()=>{ callback() ; },300) ; } render(){ const { text , onRemove } = this.props ; return ( <div ref={this.getRef} onClick={onRemove} className={styles.item}> {text} </div> ) } } export class App extends Component{ ... , render(){ const { items } = this.state ; return ( <div> ... , <div className="list"> { items.map((item,i)=>( <Item key={item} text={item} ...otherProps /> )) } </div> </div> ) } }
style.css:
.example-enter { opacity: 0.01; } .example-enter.example-enter-active { opacity: 1; transition: opacity 500ms ease-in; } .example-leave { opacity: 1; } .example-leave.example-leave-active { opacity: 0.01; transition: opacity 300ms ease-in; }
相比于ReactCSSTransitionGroup
,咱们须要本身去控制组件的动画生命周期,增长了必定的复杂度,可是对自动以动画,又能提供更好的灵活度。能够根据业务场景,选择合适的Group
,去实现咱们的需求。
一般状况下,咱们用ReactCSSTransitionGroup
就能知足较多的业务场景了,而且从实现上会容易不少。
react-motion
提供了5个API接口:
跟其余React动画库同样,react-motion
也提供React组件去包裹须要动画的业务组件。其中:
Motion
组件只接受一个children
组件StaggeredMotion
组件接受一组children
组件TranstionMotion
组件能够支持其children
组件mounting
和unmounting
定义动画仍然是 todo-list 的例子,react-motion
的实现也很是简单:
import React,{ Component } from 'react' ; import { Motion , spring } from 'react-motion'; export default class App extends Component{ ... , render(){ const { items } = this.state ; return ( <div> ... , <div className="list"> { items.map((item)=>{ return ( <Motion defaultStyle={{opacity:0}} style={{opacity:spring(1)}}> { interpolatingStyle => ( <div key={item} className="item" style={interpolatingStyle} > {item} </div> ) } </Motion> ) }) } </div> </div> ) } }
经过上述简单的代码,便可实现每一个Item在mounting
的时候渐现的效果。
另外一方面,观察上述实现,咱们不难发现,react-motion
不只仅支持React web应用,它应该也能轻松的应用到React-Native中。由于其React组件只是根据提供的defaultStyle
及style
属性,生成动画的数据,业务应用中拿到生成的数据后根据须要添加须要动画的组件样式。react-motion
在web应用中性能表现较为可观,在React-Native应用中的性能表现,有待咱们调研。
除了上述简单的动画应用,react-motion
在复杂动画的实现方面,表现很是优越。下面的动图是react-motion
实现的一个动画演示:
这个示例展现了部分react-motion
的能力,更多关于react-motion
的应用就让咱们一块儿去发现吧。
固然React动画相关的库还有不少,本文不过多介绍。经过上述对这些库的使用作简单介绍,笔者但愿经过对它们实现进行分析,让读者能更好的理解与掌握,能对React动画的实现原理和实现方式,有更为清晰的认识。
可是对相关代码的研究,深刻度还不足以给读者朋友分享,因此暂时留坑,后续会将相关源码的学习,记录在文档React动画的实现原理一文中,并计划添加从零开始,实现React动画文章做为学习成果。若是对React动画保有兴趣,能够关注这两篇文章的后续内容。