不論是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動畫保有興趣,能夠關注這兩篇文章的後續內容。