真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

React中怎么實(shí)現(xiàn)常見(jiàn)的動(dòng)畫(huà)

這篇文章主要介紹React中怎么實(shí)現(xiàn)常見(jiàn)的動(dòng)畫(huà),文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

成都創(chuàng)新互聯(lián)長(zhǎng)期為上千客戶(hù)提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開(kāi)放共贏(yíng)平臺(tái),與合作伙伴共同營(yíng)造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為內(nèi)丘企業(yè)提供專(zhuān)業(yè)的網(wǎng)站制作、成都網(wǎng)站制作,內(nèi)丘網(wǎng)站改版等技術(shù)服務(wù)。擁有10余年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開(kāi)發(fā)。

現(xiàn)在,用戶(hù)對(duì)于前端頁(yè)面的要求已經(jīng)不能滿(mǎn)足于實(shí)現(xiàn)功能,更要有顏值,有趣味。除了整體 UI 的美觀(guān),在合適的地方添加合適的動(dòng)畫(huà)效果往往比靜態(tài)頁(yè)面更具有表現(xiàn)力,達(dá)到更自然的效果。比如,一個(gè)簡(jiǎn)單的 loading 動(dòng)畫(huà)或者頁(yè)面切換效果不僅能緩解用戶(hù)的等待情緒,甚至通過(guò)使用品牌 logo 等形式,默默達(dá)到品牌宣傳的效果。

React 作為最近幾年比較流行的前端開(kāi)發(fā)框架,提出了虛擬 DOM 概念,所有 DOM 的變化都先發(fā)生在虛擬 DOM 上,通過(guò) DOM diff 來(lái)分析網(wǎng)頁(yè)的實(shí)際變化,然后反映在真實(shí) DOM 上,從而極大地提升網(wǎng)頁(yè)性能。然而,在動(dòng)畫(huà)實(shí)現(xiàn)方面,React 作為框架并不會(huì)直接給組件提供動(dòng)畫(huà)效果,需要開(kāi)發(fā)者自行實(shí)現(xiàn),而傳統(tǒng) web 動(dòng)畫(huà)大多數(shù)都通過(guò)直接操作實(shí)際 DOM 元素來(lái)實(shí)現(xiàn),這在 React 中顯然是不被提倡的。那么,在 React 中動(dòng)畫(huà)都是如何實(shí)現(xiàn)的呢?

所有動(dòng)畫(huà)的本質(zhì)都是連續(xù)修改 DOM 元素的一個(gè)或者多個(gè)屬性,使其產(chǎn)生連貫的變化效果,從而形成動(dòng)畫(huà)。在 React 中實(shí)現(xiàn)動(dòng)畫(huà)本質(zhì)上與傳統(tǒng) web 動(dòng)畫(huà)一樣,仍然是兩種方式: 通過(guò) css3 動(dòng)畫(huà)實(shí)現(xiàn)和通過(guò) js 修改元素屬性。只不過(guò)在具體實(shí)現(xiàn)時(shí),要更為符合 React 的框架特性,可以概括為幾類(lèi):

  1. 基于定時(shí)器或 requestAnimationFrame(RAF) 的間隔動(dòng)畫(huà);

  2. 基于 css3 的簡(jiǎn)單動(dòng)畫(huà);

  3. React 動(dòng)畫(huà)插件 CssTransitionGroup;

  4. 結(jié)合 hook 實(shí)現(xiàn)復(fù)雜動(dòng)畫(huà);

  5. 其他第三方動(dòng)畫(huà)庫(kù)。

一、基于定時(shí)器或 RAF 的間隔動(dòng)畫(huà)

最早,動(dòng)畫(huà)的實(shí)現(xiàn)都是依靠定時(shí)器 setInterval , setTimeout 或者 requestAnimationFrame (RAF) 直接修改 DOM 元素的屬性。不熟悉 React 特性的開(kāi)發(fā)者可能會(huì)習(xí)慣性地通過(guò) ref 或者 findDOMNode() 獲取真實(shí)的 DOM 節(jié)點(diǎn),直接修改其樣式。然而,通過(guò) ref 直接獲取真實(shí) DOM 并對(duì)其操作是是不被提倡使用,應(yīng)當(dāng)盡量避免這種操作。

因此,我們需要將定時(shí)器或者 RAF 等方法與 DOM 節(jié)點(diǎn)屬性通過(guò) state 聯(lián)系起來(lái)。首先,需要提取出與變化樣式相關(guān)的屬性,替換為 state ,然后在合適的生命周期函數(shù)中添加定時(shí)器或者 requestAnimationFrame 不斷修改 state ,觸發(fā)組件更新,從而實(shí)現(xiàn)動(dòng)畫(huà)效果。

示例

以一個(gè)進(jìn)度條為例,代碼如下所示:

// 使用requestAnimationFrame改變state
import React, { Component } from 'react';

export default class Progress extends Component { 
  constructor(props) {
    super(props);
    this.state = {
      percent: 10
    };
  }

  increase = () => {
    const percent = this.state.percent;
    const targetPercent = percent >= 90 ? 100 : percent + 10;
    const speed = (targetPercent - percent) / 400;
    let start = null;
    const animate = timestamp => {
      if (!start) start = timestamp;
      const progress = timestamp - start;
      const currentProgress = Math.min(parseInt(speed * progress + percent, 10), targetPercent);
      this.setState({
        percent: currentProgress
      });
      if (currentProgress < targetPercent) {
        window.requestAnimationFrame(animate);
      }
    };
    window.requestAnimationFrame(animate);
  }

  decrease = () => {
    const percent = this.state.percent;
    const targetPercent = percent < 10 ? 0 : percent - 10;
    const speed = (percent - targetPercent) / 400;
    let start = null;
    const animate = timestamp => {
      if (!start) start = timestamp;
      const progress = timestamp - start;
      const currentProgress = Math.max(parseInt(percent - speed * progress, 10), targetPercent);
      this.setState({
          percent: currentProgress
        });
      if (currentProgress > targetPercent) {
        window.requestAnimationFrame(animate);
      }
    };
    window.requestAnimationFrame(animate);
  }

  render() {
    const { percent } = this.state;

    return (
      
                                
          
          {percent}%
        
                   -           +                     );   } }

在示例中,我們?cè)?increasedecrease 函數(shù)中構(gòu)建線(xiàn)性過(guò)渡函數(shù) animationrequestAnimationFrame 在瀏覽器每次重繪前執(zhí)行會(huì)執(zhí)行過(guò)渡函數(shù),計(jì)算當(dāng)前進(jìn)度條 width 屬性并更新該 state ,使得進(jìn)度條重新渲染。該示例的效果如下所示:

React中怎么實(shí)現(xiàn)常見(jiàn)的動(dòng)畫(huà)

這種實(shí)現(xiàn)方式在使用 requestAnimationFrame 時(shí)性能不錯(cuò),完全使用純 js 實(shí)現(xiàn),不依賴(lài)于 css,使用定時(shí)器時(shí)可能出現(xiàn)掉幀卡頓現(xiàn)象。此外,還需要開(kāi)發(fā)者根據(jù)速度函數(shù)自己計(jì)算狀態(tài),比較復(fù)雜。

二、基于 css3 的簡(jiǎn)單動(dòng)畫(huà)

當(dāng) css3 中的 animationtransition 出現(xiàn)和普及后,我們可以輕松地利用 css 實(shí)現(xiàn)元素樣式的變化,而不用通過(guò)人為計(jì)算實(shí)時(shí)樣式。

示例

我們?nèi)砸陨厦娴倪M(jìn)度條為例,使用 css3 實(shí)現(xiàn)進(jìn)度條動(dòng)態(tài)效果,代碼如下所示:

import React, { Component } from 'react';

export default class Progress extends Component { 
  constructor(props) {
    super(props);
    this.state = {
      percent: 10
    };
  }

  increase = () => {
    const percent = this.state.percent + 10;
    this.setState({
      percent: percent > 100 ? 100 : percent,
    })
  }

  decrease = () => {
    const percent = this.state.percent - 10;
    this.setState({
      percent: percent < 0 ? 0 : percent,
    })
  }

  render() {
    // 同上例, 省略
    ....
  }
}
.progress-inner {
 transition: width 400ms cubic-bezier(0.08, 0.82, 0.17, 1);
 // 其他樣式同上,省略
 ...
}

在示例中, increasedecrease 函數(shù)中不再計(jì)算 width ,而是直接設(shè)置增減后的寬度。需要注意的是,在 css 樣式中設(shè)置了 transition 屬性,該屬性在其指定的 transition-property 發(fā)生變化時(shí)自動(dòng)實(shí)現(xiàn)樣式的動(dòng)態(tài)變化效果,并且可以設(shè)置不同的速度效果的速度曲線(xiàn)。該示例的效果如下圖所示,可以發(fā)現(xiàn),與上一個(gè)例子不同的是,右側(cè)的進(jìn)度數(shù)據(jù)是直接變化為目標(biāo)數(shù)字,沒(méi)有具體的變化過(guò)程,而進(jìn)度條的動(dòng)態(tài)效果因?yàn)椴辉偈蔷€(xiàn)性變化,效果更為生動(dòng)。

React中怎么實(shí)現(xiàn)常見(jiàn)的動(dòng)畫(huà)

基于 css3 的實(shí)現(xiàn)方式具有較高的性能,代碼量少,但是只能依賴(lài)于 css 效果,對(duì)于復(fù)雜動(dòng)畫(huà)也很難實(shí)現(xiàn)。此外,通過(guò)修改 state 實(shí)現(xiàn)動(dòng)畫(huà)效果,只能作用于已經(jīng)存在于 DOM 樹(shù)中的節(jié)點(diǎn)。如果想用這種方式為組件添加入場(chǎng)和離場(chǎng)動(dòng)畫(huà),需要維持至少兩個(gè) state 來(lái)實(shí)現(xiàn)入場(chǎng)和離場(chǎng)動(dòng)畫(huà),其中一個(gè) state 用于控制元素是否顯示,另一個(gè) state 用于控制元素在動(dòng)畫(huà)中的變化屬性。在這種情況下,開(kāi)發(fā)者需要花費(fèi)大量精力來(lái)維護(hù)組件的動(dòng)畫(huà)邏輯,十分復(fù)雜繁瑣。

三、React 動(dòng)畫(huà)插件 CssTransitionGroup

React 曾為開(kāi)發(fā)者提供過(guò)動(dòng)畫(huà)插件 react-addons-css-transition-group ,后交由社區(qū)維護(hù),形成現(xiàn)在的 react-transition-group ,該插件可以方便地實(shí)現(xiàn)組件的入場(chǎng)和離場(chǎng)動(dòng)畫(huà),使用時(shí)需要開(kāi)發(fā)者額外安裝。 react-transition-group 包含 CSSTransitionGroupTransitionGroup 兩個(gè)動(dòng)畫(huà)插件,其中,后者是底層 api,前者是后者的進(jìn)一步封裝,可以較為便捷地實(shí)現(xiàn) css 動(dòng)畫(huà)。

示例

以一個(gè)動(dòng)態(tài)增加tab的為例,代碼如下:

import React, { Component } from 'react'; 
import { CSSTransitionGroup } from 'react-transition-group';

let uid = 2; 
export default class Tabs extends Component { 
  constructor(props) {
    super(props);
    this.state = {
      activeId: 1,
      tabData: [{
        id: 1,
        panel: '選項(xiàng)1'
      }, {
        id: 2,
        panel: '選項(xiàng)2'
      }]
    };
  }

  addTab = () => {
    // 添加tab代碼
    ...
  }

  deleteTab = (id) => {
    // 刪除tab代碼
    ...
  }

  render() {
    const { tabData, activeId } = this.state;

    const renderTabs = () => {
      return tabData.map((item, index) => {
        return (
          
            {item.panel}              this.deleteTab(item.id)}>?           
        );       })     }     return (       
                               {renderTabs()}                      +         
                   cont                     );   } }
/* tab動(dòng)態(tài)增加動(dòng)畫(huà) */
.tabs-wrap-enter {
 opacity: 0.01;
}

.tabs-wrap-enter.tabs-wrap-enter-active {
 opacity: 1;
 transition: all 500ms ease-in;
}

.tabs-wrap-leave {
 opacity: 1;
}

.tabs-wrap-leave.tabs-wrap-leave-active {
 opacity: 0.01;
 transition: all 500ms ease-in;
}

CSSTransitionGroup 可以為其子節(jié)點(diǎn)添加額外的 css 類(lèi),然后通過(guò) css 動(dòng)畫(huà)達(dá)到入場(chǎng)和離場(chǎng)動(dòng)畫(huà)效果。為了給每個(gè) tab 節(jié)點(diǎn)添加動(dòng)畫(huà)效果,需要先將它們包裹在 CSSTransitionGroup 組件中。 當(dāng)設(shè)定 transitionName 屬性為 'tabs-wrapper' , transitionEnterTimeout 為400毫秒后,一旦 CSSTransitionGroup 中新增節(jié)點(diǎn),該新增節(jié)點(diǎn)會(huì)在出現(xiàn)時(shí)被添加上 css 類(lèi) 'tabs-wrapper-enter' ,然后在下一幀時(shí)被添加上 css 類(lèi) 'tabs-wrapper-enter-active' 。由于這兩個(gè) css 類(lèi)中設(shè)定了不同的透明度和 css3 transition 屬性,所以節(jié)點(diǎn)實(shí)現(xiàn)了透明度由小到大的入場(chǎng)效果。400毫秒后 css 類(lèi) 'tabs-wrapper-enter''tabs-wrapper-enter-active' 將會(huì)同時(shí)被移除,節(jié)點(diǎn)完成整個(gè)入場(chǎng)動(dòng)畫(huà)過(guò)程。離場(chǎng)動(dòng)畫(huà)的實(shí)現(xiàn)類(lèi)似于入場(chǎng)動(dòng)畫(huà),只不過(guò)被添加的 css 類(lèi)名為 'tabs-wrapper-leave''tabs-wrapper-leave-active' 。該示例效果如下圖所示:

React中怎么實(shí)現(xiàn)常見(jiàn)的動(dòng)畫(huà)

CSSTransitionGroup 支持以下7個(gè)屬性:

React中怎么實(shí)現(xiàn)常見(jiàn)的動(dòng)畫(huà)

其中,入場(chǎng)和離場(chǎng)動(dòng)畫(huà)是默認(rèn)開(kāi)啟的,使用時(shí)需要設(shè)置 transitionEnterTimeouttransitionLeaveTimeout 。值得注意的是, CSSTransitionGroup 還提供出現(xiàn)動(dòng)畫(huà)(appear),使用時(shí)需要設(shè)置 transitionAppearTimeout 。那么,出現(xiàn)動(dòng)畫(huà)和入場(chǎng)動(dòng)畫(huà)有什么區(qū)別呢?當(dāng)設(shè)定 transitionAppeartrue 時(shí), CSSTransitionGroup初次渲染時(shí),會(huì)添加一個(gè)出現(xiàn)階段。在該階段中, CSSTransitionGroup 的已有子節(jié)點(diǎn)都會(huì)被相繼添加 css 類(lèi) 'tabs-wrapper-appear''tabs-wrapper-appear-active' ,實(shí)現(xiàn)出現(xiàn)動(dòng)畫(huà)效果。因此, 出現(xiàn)動(dòng)畫(huà)僅適用于 CSSTransitionGroup 在初次渲染時(shí)就存在的子節(jié)點(diǎn) ,一旦 CSSTransitionGroup 完成渲染,其子節(jié)點(diǎn)就只可能有入場(chǎng)動(dòng)畫(huà)(enter),不可能有出現(xiàn)動(dòng)畫(huà)(appear)。

此外,使用 CSSTransitionGroup 需要注意以下幾點(diǎn):

  1. CSSTransitionGroup 默認(rèn)在 DOM 樹(shù)中生成一個(gè) span 標(biāo)簽包裹其子節(jié)點(diǎn),如果想要使用其他 html 標(biāo)簽,可設(shè)定 CSSTransitionGroupcomponent 屬性;

  2. CSSTransitionGroup 的子元素必須添加 key 值才會(huì)在節(jié)點(diǎn)發(fā)生變化時(shí),準(zhǔn)確地計(jì)算出哪些節(jié)點(diǎn)需要添加入場(chǎng)動(dòng)畫(huà),哪些節(jié)點(diǎn)需要添加離場(chǎng)動(dòng)畫(huà);

  3. CSSTransitionGroup 的動(dòng)畫(huà)效果只作用于直接子節(jié)點(diǎn),不作用于其孫子節(jié)點(diǎn);

  4. 動(dòng)畫(huà)的結(jié)束時(shí)間不以 css 中 transition-duration 為準(zhǔn),而是以 transitionEnterTimeout , transitionLeaveTimeoutTransitionAppearTimeout 為準(zhǔn),因?yàn)槟承┣闆r下 transitionend 事件不會(huì)被觸發(fā),詳見(jiàn) MDN transitionend 。

CSSTransitionGroup 實(shí)現(xiàn)動(dòng)畫(huà)的優(yōu)點(diǎn)是:

  1. 簡(jiǎn)單易用,可以方便快捷地實(shí)現(xiàn)元素的入場(chǎng)和離場(chǎng)動(dòng)畫(huà);

  2. 與 React 結(jié)合,性能比較好。

CSSTransitionGroup 缺點(diǎn)也十分明顯:

  1. 局限于出現(xiàn)動(dòng)畫(huà),入場(chǎng)動(dòng)畫(huà)和離場(chǎng)動(dòng)畫(huà);

  2. 由于需要制定 transitionName ,靈活性不夠;

  3. 只能依靠 css 實(shí)現(xiàn)簡(jiǎn)單的動(dòng)畫(huà)。

四、結(jié)合 hook 實(shí)現(xiàn)復(fù)雜動(dòng)畫(huà)

在實(shí)際項(xiàng)目中,可能需要一些更炫酷的動(dòng)畫(huà)效果,這些效果僅依賴(lài)于 css3 往往較難實(shí)現(xiàn)。此時(shí),我們不妨借助一些成熟的第三方庫(kù),如 jQuery 或 GASP,結(jié)合 React 組件中的生命周期鉤子方法 hook 函數(shù),實(shí)現(xiàn)復(fù)雜動(dòng)畫(huà)效果。除了 React 組件正常的生命周期外, CSSTransitionGroup 的底層 api TransitonGroup 還為其子元素額外提供了一系列特殊的生命周期 hook 函數(shù),在這些 hook 函數(shù)中結(jié)合第三方動(dòng)畫(huà)庫(kù)可以實(shí)現(xiàn)豐富的入場(chǎng)、離場(chǎng)動(dòng)畫(huà)效果。

TransisitonGroup 分別提供一下六個(gè)生命周期 hook 函數(shù):

  1. componentWillAppear(callback)

  2. componentDidAppear()

  3. componentWillEnter(callback)

  4. componentDidEnter()

  5. componentWillLeave(callback)

  6. componentDidLeave()

它們的觸發(fā)時(shí)機(jī)如圖所示:

React中怎么實(shí)現(xiàn)常見(jiàn)的動(dòng)畫(huà)

示例

GASP 是一個(gè) flash 時(shí)代發(fā)展至今的動(dòng)畫(huà)庫(kù),借鑒視頻幀的概念,特別適合做長(zhǎng)時(shí)間的序列動(dòng)畫(huà)效果。本文中,我們用 TransitonGroupreact-gsap-enhancer (一個(gè)可以將 GSAP 應(yīng)用于 React 的增強(qiáng)庫(kù))完成一個(gè)圖片畫(huà)廊,代碼如下:

import React, { Component } from 'react'; 
import { TransitionGroup } from 'react-transition-group'; 
import GSAP from 'react-gsap-enhancer' 
import { TimelineMax, Back, Sine } from 'gsap';

class Photo extends Component { 
  constructor(props) {
    super(props);
  }

  componentWillEnter(callback) {
    this.addAnimation(this.enterAnim, {callback: callback})
  }

  componentWillLeave(callback) {
    this.addAnimation(this.leaveAnim, {callback: callback})
  }

  enterAnim = (utils) => {
    const { id } = this.props;
    return new TimelineMax()
      .from(utils.target, 1, {
        x: `+=${( 4 - id ) * 60}px`,
        autoAlpha: 0,
        onComplete: utils.options.callback,
      }, id * 0.7);
  }

  leaveAnim = (utils) => {
    const { id } = this.props;
    return new TimelineMax()
      .to(utils.target, 0.5, {
        scale: 0,
        ease: Sine.easeOut,
        onComplete: utils.options.callback,
      }, (4 - id) * 0.7);
  }

  render() {
    const { url } = this.props;
    return (
      
        
      
    )
  }
}

const WrappedPhoto = GSAP()(Photo);

export default class Gallery extends Component { 
  constructor(props) {
    super(props);
    this.state = {
      show: false,
      photos: [{
        id: 1,
        url: 'http://img4.imgtn.bdimg.com/it/u=1032683424,3204785822&fm=214&gp=0.jpg'
      }, {
        id: 2,
        url: 'http://imgtu.5011.net/uploads/content/20170323/7488001490262119.jpg'
      }, {
        id: 3,
        url: 'http://tupian.enterdesk.com/2014/lxy/2014/12/03/18/10.jpg'
      }, {
        id: 4,
        url: 'http://img4.imgtn.bdimg.com/it/u=360498760,1598118672&fm=27&gp=0.jpg'
      }]
    };
  }

  toggle = () => {
    this.setState({
      show: !this.state.show
    })
  }

  render() {
    const { show, photos } = this.state;

    const renderPhotos = () => {
      return photos.map((item, index) => {
        return ;
      })
    }

    return (
      
        toggle                    {show && renderPhotos()}                
    );   } }

在該示例中,我們?cè)谧咏M件 PhotocomponentWillEntercomponentWillLeave 兩個(gè) hook 函數(shù)中為每個(gè)子組件添加了入場(chǎng)動(dòng)畫(huà) enterAnim 和 離場(chǎng)動(dòng)畫(huà) LeaveAnim 。在入場(chǎng)動(dòng)畫(huà)中,使用 TimeLineMax.from(target, duration, vars, delay) 方式建立時(shí)間軸動(dòng)畫(huà),指定了每個(gè)子組件的動(dòng)畫(huà)移動(dòng)距離隨 id 增大而減小,延期時(shí)間隨著 id 增大而增大,離場(chǎng)動(dòng)畫(huà)中每個(gè)子組件的延期時(shí)間隨著 id 增大而減小,從而實(shí)現(xiàn)根據(jù)組件 id 不同具有不同的動(dòng)畫(huà)效果。實(shí)際使用時(shí),你可以根據(jù)需求對(duì)任一子組件添加不同的效果。該示例的效果如下圖所示:

React中怎么實(shí)現(xiàn)常見(jiàn)的動(dòng)畫(huà)

在使用 TransitionGroup 時(shí),在 componentnWillAppear(callback) , componentnWillEntercallback) , componentnWillLeave(callback) 函數(shù)中一定要 在函數(shù)邏輯結(jié)束后調(diào)用 callback ,以保證 TransitionGroup 能正確維護(hù)子節(jié)點(diǎn)的狀態(tài)序列 。

結(jié)合 hook 實(shí)現(xiàn)動(dòng)畫(huà)可以支持各種復(fù)雜動(dòng)畫(huà),如時(shí)間序列動(dòng)畫(huà)等,由于依賴(lài)第三方庫(kù),往往動(dòng)畫(huà)效果比較流暢,用戶(hù)體驗(yàn)較好。但是第三方庫(kù)的引入,需要開(kāi)發(fā)者額外學(xué)習(xí)對(duì)應(yīng)的 api,也提升了代碼復(fù)雜度。

五、其他第三方動(dòng)畫(huà)庫(kù)

此外,還有很多優(yōu)秀的第三方動(dòng)畫(huà)庫(kù),如 react-motion ,Animated, velocity-react 等,這些動(dòng)畫(huà)庫(kù)在使用時(shí)也各有千秋。

Animated

Animated 是一個(gè)跨平臺(tái)的動(dòng)畫(huà)庫(kù),兼容 React 和 React Native。由于在動(dòng)畫(huà)過(guò)程中,我們只關(guān)心動(dòng)畫(huà)的初始狀態(tài)、結(jié)束狀態(tài)和變化函數(shù),并不關(guān)心每個(gè)時(shí)刻元素屬性的具體值,所以 Animatied 采用聲明式的動(dòng)畫(huà),通過(guò)它提供的特定方法計(jì)算 css 對(duì)象,并傳入 Animated.div 實(shí)現(xiàn)動(dòng)畫(huà)效果。

示例

我們使用 Animated 實(shí)現(xiàn)一個(gè)圖片翻轉(zhuǎn)的效果,代碼如下。

import React, { Component } from 'react'; 
import Animated from 'animated/lib/targets/react-dom';

export default class PhotoPreview extends Component { 
  constructor(props) {
    super(props);
    this.state = {
      anim: new Animated.Value(0)
    };
  }

  handleClick = () => {
    const { anim } = this.state;
    anim.stopAnimation(value => {
      Animated.spring(anim, {
        toValue: Math.round(value) + 1
      }).start();
    });
  }

  render() {
    const { anim } = this.state;

    const rotateDegree = anim.interpolate({
      inputRange: [0, 4],
      outputRange: ['0deg', '360deg']
    });

    return (
      
        向右翻轉(zhuǎn)                                    
    );   } }

在該示例中,我們希望實(shí)現(xiàn)每點(diǎn)擊一次按鈕,圖片向右旋轉(zhuǎn)90°。在組件初始化時(shí)新建了一個(gè)初始值為 0 的 Animated 對(duì)象 this.state.anim ,在 render 函數(shù)中通過(guò)插值函數(shù) interpolate 根據(jù) Animated 對(duì)象的當(dāng)前值計(jì)算得到對(duì)應(yīng)的旋轉(zhuǎn)角度 rotateDegree 。我們假設(shè)每點(diǎn)擊一次按鈕, Animated 對(duì)象的值加 1,相應(yīng)地圖像轉(zhuǎn)動(dòng)90°,所以,設(shè)置 interpolate 函數(shù)的輸入?yún)^(qū)間為[0, 4],輸出區(qū)間為['0deg', '360deg']進(jìn)行線(xiàn)性插值。如果 Animated 對(duì)象當(dāng)前值為 2,對(duì)應(yīng)的旋轉(zhuǎn)角度就是 180deg。在組件渲染結(jié)構(gòu)中,需要使用 Animated.div 包裹動(dòng)畫(huà)節(jié)點(diǎn),并將變化的元素屬性封裝為 css 對(duì)象作為 stlye 傳入 Animated.div 中。在點(diǎn)擊事件中,考慮到按鈕可以多次連續(xù)點(diǎn)擊,我們首先使用 stopAnimation 停止當(dāng)前動(dòng)畫(huà),并獲取 Animated 對(duì)象的當(dāng)前值 value ,隨后使用 Animated.spring 函數(shù)開(kāi)啟一次彈簧動(dòng)畫(huà)過(guò)程,從而實(shí)現(xiàn)一個(gè)流暢的動(dòng)畫(huà)效果。由于每次轉(zhuǎn)動(dòng)停止時(shí),我們希望圖片的翻轉(zhuǎn)角度都是90°的整數(shù)倍,所以需要對(duì) Animated.spring 的終止值進(jìn)行取整。最終我們實(shí)現(xiàn)了如下效果:

React中怎么實(shí)現(xiàn)常見(jiàn)的動(dòng)畫(huà)

使用時(shí)需要注意一下幾點(diǎn):

  1. Animated 對(duì)象的值和其插值結(jié)果只能作用于 Animated.div 節(jié)點(diǎn);

  2. interpolate 默認(rèn)會(huì)根據(jù)輸入?yún)^(qū)間和輸出區(qū)間進(jìn)行線(xiàn)性插值,如果輸入值超出輸入?yún)^(qū)間不受影響,插值結(jié)果默認(rèn)會(huì)根據(jù)輸出區(qū)間向外延展插值,可以通過(guò)設(shè)置 extrapolate 屬性限制插值結(jié)果區(qū)間。

Animated 在動(dòng)畫(huà)過(guò)程中不直接修改組件 state ,而是通過(guò)其新建對(duì)象的組件和方法直接修改元素的屬性,不會(huì)重復(fù)觸發(fā) render 函數(shù),是 React Native 中非常穩(wěn)定的動(dòng)畫(huà)庫(kù)。但是在 React 中存在低版本瀏覽器兼容問(wèn)題,且具有一定學(xué)習(xí)成本。

結(jié)語(yǔ)

當(dāng)我們?cè)?React 中實(shí)現(xiàn)動(dòng)畫(huà)時(shí),首先要考量動(dòng)畫(huà)的難易程度和使用場(chǎng)景,對(duì)于簡(jiǎn)單動(dòng)畫(huà),優(yōu)先使用 css3 實(shí)現(xiàn),其次是基于 js 的時(shí)間間隔動(dòng)畫(huà)。如果是元素入場(chǎng)動(dòng)畫(huà)和離場(chǎng)動(dòng)畫(huà),則建議結(jié)合 CSSTransitionGroup 或者 TransitionGroup 實(shí)現(xiàn)。當(dāng)要實(shí)現(xiàn)的動(dòng)畫(huà)效果較為復(fù)雜時(shí),不妨嘗試一些優(yōu)秀的第三方庫(kù),打開(kāi)精彩的動(dòng)效大門(mén)。

以上是“React中怎么實(shí)現(xiàn)常見(jiàn)的動(dòng)畫(huà)”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!


新聞標(biāo)題:React中怎么實(shí)現(xiàn)常見(jiàn)的動(dòng)畫(huà)
文章起源:http://weahome.cn/article/jigepc.html

在線(xiàn)咨詢(xún)

微信咨詢(xún)

電話(huà)咨詢(xún)

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部