讓React運用“動”起來

WEB運用中動畫很主要

不管是web運用照樣原生運用,也不論是PC端運用照樣挪動端運用,動畫都扮演了一個主要的角色。

只管動畫並不會增添運用的現實動能,但一個好的動畫,一個流通且文雅,挑選在適當機遇湧現的動畫,能為運用增色不少,能很好的指導用戶舉行下一步操縱,讓運用的場景切換更合理。一個小小的細節動畫,就可以幾個條理的提拔運用的用戶體驗。

舉個簡樸的例子,運用中最罕見的頁面間切換,假如缺乏切換動畫,那就會是這個模樣:

《讓React運用“動”起來》

異常僵硬,頁面的湧現顯得異常高聳。作為對照,我們可以看下增添了動畫的頁面切換是什麼模樣的呢:

《讓React運用“動”起來》

增添了用戶預期,也能較好的提醒用戶頁面的層級關聯。

再舉個彈窗的例子,先放兩個對照圖,左側是無動畫的結果,右側是增添完動畫的結果:

《讓React運用“動”起來》《讓React運用“動”起來》

動畫雖然沒有增添什麼現實可見的功用,然則經由歷程對照,不難發明,動畫的增添,讓彈窗的湧現顯得膩滑天然,讓頁面的場景替代有一個歷程,削減高聳感,讓用戶體驗感覺增色不少不是嗎?

固然有可以因為錄製的題目,動畫結果不是很明顯,你可以有差別的意見。

動畫完成的基礎道理

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*情勢下的動畫完成

這裏的MV*情勢我們不展開說,特指React中動畫的完成。React因為加入了假造DOM等諸多特徵,而且其開闢情勢讓開闢者不須要或許不引薦直接接觸到實在的DOM構造。所以其動畫完成,與通例的開闢體式格局下的動畫完成,存在肯定得差別。

動畫的完成終究肯定是落地到操縱DOM,MV*情勢的框架則是數據驅動DOM的展現。假如我們因為動畫完成的須要,對DOM的操縱湧現題目,勢必會影響到運用的相干操縱。我們先不去深切探討怎樣處理這個題目,先看看React官方和社區對這個題目是怎樣處理的,讓我們能先給我們的React運用增添上須要的動畫。

由淺及深,我們先學會怎樣運用,再去相識內部的完成道理,從而依據運用本身需求,能完成自定義的動畫,能完成更加龐雜的交互動畫等。

React中我們怎樣增添動畫

React的動畫庫中,比較經常使用的是react-addons-css-transition-groupreact-addons-transition-group 以及react-motion 。个中, react-addons-css-transition-groupreact-addons-transition-groupHigh-Level API庫,react-addons-css-transtion-group是基於react-addons-transition-group的上層封裝。現在react-addons-css-transition-groupreact-addons-transition-group合併成一個庫,叫react-transition-group

react-transition-group@v1.x版本中的API, 基礎堅持與兩個零丁庫的API情勢一致,但@v2.x版本中的API變化較大,並不能完全切換,這個須要注重。本文的示例是以自力庫,也就是類react-transtion-group@v1.xAPI供應的。

另一個經常使用的React動畫庫是react-motion 。該庫具有異常棒的特徵,可以創建出異常細緻的動畫,接着往下看,會引見下基礎的運用,然後參照其官方文檔,置信可以完成出大多數你想要的動畫的。

1. ReactCSSTransitionGroup

react-addons-css-transition-group,平常稱其export的組件為ReactCSSTransitionGroup,它供應一種聲明的體式格局來定義CSS動畫ReactCSSTransitionGroup子組件必需大於或即是1個,不能為空。

ReactCSSTranstionGroup組件暴露的屬性有:

  • transitionAppear/transitionEnter/transitionLeave: Boolean 範例,標識是不是開啟動畫
  • transitionAppearTimeout/transitionEnterTimeout/transitionLeaveTimeout: 定義各階段動畫的時長
  • transitionName:自定義各階段動畫的 CSS 款式名
  • component: ReactCSSTranstion以什麼組件包裹(wrap)子組件,默以為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才準確的mountingunmounting子組件。
  • 自定義的動畫時長,須要與CSS款式中定義的動畫時長對應上。

關於react-addons-css-transition-group,知乎這篇文章CSS 動畫及其在 React 中的運用有較為細緻的引見。

2. ReactTransitionGroup

react-addons-transition-groupreact-addons-css-transition-grouplow-level API,其供應動畫實行中須要的各生命周期函數:

  • componentWillAppear(): componentDidMount時實行, 襯着TransitionGroup時實行而且只會實行一次。
  • componentDidAppear(): 傳給componentWillAppear的callback實行后實行。
  • componentWillEnter(): componentDidMount時實行,子組件增添進TransitionGroup時實行。
  • componentDidEnter(): 傳給componentWillEnter的callback實行后實行。
  • componentWillLeave(): 子組件從TransitionGroup中移除時實行,Though the child has been removed, TransitionGroup will keep it in the DOM until callback is called.
  • componentDidLeave(): componentWillLeave的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就可以滿足較多的營業場景了,而且從完成上會輕易許多。

3. ReactMotion

react-motion供應了5個API接口:

  • spring: 動畫天生要領
  • Motion: React 組件
  • StaggeredMotion: React 組件
  • TransitionMotion: React 組件
  • presets: spring要領的設置項

跟其他React動畫庫一樣,react-motion也供應React組件去包裹須要動畫的營業組件。个中:

  • Motion組件只接收一個children組件
  • StaggeredMotion組件接收一組children組件
  • TranstionMotion組件可以支撐其children組件mountingunmounting定義動畫

仍然是 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組件只是依據供應的defaultStylestyle屬性,天生動畫的數據,營業運用中拿到天生的數據后依據須要增添須要動畫的組件款式。react-motion在web運用中機能表現較為可觀,在React-Native運用中的機能表現,有待我們調研。

除了上述簡樸的動畫運用,react-motion在龐雜動畫的完成方面,表現異常優勝。下面的動圖是react-motion完成的一個動畫演示:

《讓React運用“動”起來》

這個示例展現了部份react-motion的才能,更多關於react-motion的運用就讓我們一同去發明吧。

結語

固然React動畫相干的庫另有許多,本文不過量引見。經由歷程上述對這些庫的運用做簡樸引見,筆者願望經由歷程對它們完成舉行剖析,讓讀者能更好的明白與控制,能對React動畫的完成道理和完成體式格局,有更加清楚的熟悉。

然則對相干代碼的研討,深切度還不足以給讀者朋儕分享,所以臨時留坑,後續會將相干源碼的進修,記錄在文檔React動畫的完成道理一文中,並設計增添從零開始,完成React動畫文章作為進修效果。假如對React動畫保有興緻,可以關注這兩篇文章的後續內容。

    原文作者:citywall
    原文地址: https://segmentfault.com/a/1190000014634109
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞