摘要:因?yàn)槠浣M件只是根據(jù)提供的及屬性,生成動(dòng)畫的數(shù)據(jù),業(yè)務(wù)應(yīng)用中拿到生成的數(shù)據(jù)后根據(jù)需要添加需要?jiǎng)赢嫷慕M件樣式。除了上述簡(jiǎn)單的動(dòng)畫應(yīng)用,在復(fù)雜動(dòng)畫的實(shí)現(xiàn)方面,表現(xiàn)非常優(yōu)越。
WEB應(yīng)用中動(dòng)畫很重要
不管是web應(yīng)用還是原生應(yīng)用,也不論是PC端應(yīng)用還是移動(dòng)端應(yīng)用,動(dòng)畫都扮演了一個(gè)重要的角色。
盡管動(dòng)畫并不會(huì)添加應(yīng)用的實(shí)際動(dòng)能,但一個(gè)好的動(dòng)畫,一個(gè)流暢且優(yōu)雅,選擇在恰當(dāng)時(shí)機(jī)出現(xiàn)的動(dòng)畫,能為應(yīng)用增色不少,能很好的引導(dǎo)用戶進(jìn)行下一步操作,讓應(yīng)用的場(chǎng)景切換更合理。一個(gè)小小的細(xì)節(jié)動(dòng)畫,就能幾個(gè)層次的提升應(yīng)用的用戶體驗(yàn)。
舉個(gè)簡(jiǎn)單的例子,應(yīng)用中最常見(jiàn)的頁(yè)面間切換,如果缺少切換動(dòng)畫,那就會(huì)是這個(gè)樣子:
非常生硬,頁(yè)面的出現(xiàn)顯得非常突兀。作為對(duì)比,我們可以看下添加了動(dòng)畫的頁(yè)面切換是什么樣子的呢:
增加了用戶預(yù)期,也能較好的提示用戶頁(yè)面的層級(jí)關(guān)系。
再舉個(gè)彈窗的例子,先放兩個(gè)對(duì)比圖,左邊是無(wú)動(dòng)畫的效果,右邊是添加完動(dòng)畫的效果:
動(dòng)畫雖然沒(méi)有添加什么實(shí)際可見(jiàn)的功能,但是通過(guò)對(duì)比,不難發(fā)現(xiàn),動(dòng)畫的添加,讓彈窗的出現(xiàn)顯得平滑自然,讓頁(yè)面的場(chǎng)景替換有一個(gè)過(guò)程,減少突兀感,讓用戶體驗(yàn)感受增色不少不是嗎?
當(dāng)然有可能因?yàn)殇浿频膯?wèn)題,動(dòng)畫效果不是很明顯,你可能有不同的看法。動(dòng)畫實(shí)現(xiàn)的基本原理
web應(yīng)用的基本骨架是DOM,正是一個(gè)個(gè)的DOM節(jié)點(diǎn),構(gòu)建出web應(yīng)用,換句話說(shuō),就是web應(yīng)用呈現(xiàn)出來(lái)的樣子是DOM決定的(當(dāng)然這里把CSS樣式,歸納為了DOM的一部分)。所以動(dòng)畫的實(shí)現(xiàn),從本質(zhì)上來(lái)講,就是操作DOM:讓DOM在不同的時(shí)間節(jié)點(diǎn),在不同的位置、有不同的大小、透明度、呈現(xiàn)不同的背景色等,并且讓這種變化連續(xù)起來(lái),則構(gòu)成了我們能觀察到的動(dòng)畫。
基于web動(dòng)畫實(shí)現(xiàn)的基本原理,在我們直接操作DOM的時(shí)代,實(shí)現(xiàn)動(dòng)畫相對(duì)我們來(lái)說(shuō),非常直觀——只要知道怎么操作DOM即可。比如需要實(shí)現(xiàn)一個(gè)黑色背景的div方塊,1s內(nèi)從離左邊距100px的位置,移動(dòng)到離左邊距200px的位置,則我們只需要每秒控制該div的left值增加(200-100)/60px即可實(shí)現(xiàn)一個(gè)勻速的動(dòng)畫效果。怎么樣,很簡(jiǎn)單吧。
上述動(dòng)畫實(shí)現(xiàn)的方式,我們稱為JS動(dòng)畫。是由JS腳本邏輯,動(dòng)態(tài)的改變DOM的CSS屬性值。
CSS3中,添加了動(dòng)畫的實(shí)現(xiàn)的方案,所以web中第二種動(dòng)畫實(shí)現(xiàn),被我們稱為CSS動(dòng)畫。CSS動(dòng)畫,最主要的幾個(gè)CSS屬性是: transition,transform,animation,由于與本文的主題不是密切相關(guān),此處就不做詳細(xì)介紹,有興趣可以自行搜索相關(guān)文章查閱。
MV*模式下的動(dòng)畫實(shí)現(xiàn)這里的MV*模式我們不展開(kāi)說(shuō),特指React中動(dòng)畫的實(shí)現(xiàn)。React由于加入了虛擬DOM等諸多特性,并且其開(kāi)發(fā)模式讓開(kāi)發(fā)者不需要或者不推薦直接接觸到真實(shí)的DOM結(jié)構(gòu)。所以其動(dòng)畫實(shí)現(xiàn),與常規(guī)的開(kāi)發(fā)方式下的動(dòng)畫實(shí)現(xiàn),存在一定得差異。
動(dòng)畫的實(shí)現(xiàn)最終一定是落地到操作DOM,MV*模式的框架則是數(shù)據(jù)驅(qū)動(dòng)DOM的展示。如果我們因?yàn)閯?dòng)畫實(shí)現(xiàn)的需要,對(duì)DOM的操作出現(xiàn)問(wèn)題,勢(shì)必會(huì)影響到應(yīng)用的相關(guān)操作。我們先不去深入探討怎么解決這個(gè)問(wèn)題,先看看React官方和社區(qū)對(duì)這個(gè)問(wèn)題是怎么解決的,讓我們能先給我們的React應(yīng)用添加上需要的動(dòng)畫。
由淺及深,我們先學(xué)會(huì)怎么使用,再去了解內(nèi)部的實(shí)現(xiàn)原理,從而根據(jù)應(yīng)用自身需求,能實(shí)現(xiàn)自定義的動(dòng)畫,能實(shí)現(xiàn)更為復(fù)雜的交互動(dòng)畫等。
React中我們?cè)趺刺砑觿?dòng)畫React的動(dòng)畫庫(kù)中,比較常用的是react-addons-css-transition-group、react-addons-transition-group 以及react-motion 。其中, react-addons-css-transition-group是react-addons-transition-group的High-Level API庫(kù),react-addons-css-transtion-group是基于react-addons-transition-group的上層封裝。目前react-addons-css-transition-group和react-addons-transition-group合并成一個(gè)庫(kù),叫react-transition-group。
[email protected]版本中的API, 基本保持與兩個(gè)多帶帶庫(kù)的API形式一致,但@v2.x版本中的API變化較大,并不能完全切換,這個(gè)需要注意。本文的示例是以獨(dú)立庫(kù),也就是類[email protected]API提供的。
另一個(gè)常用的React動(dòng)畫庫(kù)是react-motion 。該庫(kù)擁有非常棒的特性,能夠創(chuàng)建出非常細(xì)膩的動(dòng)畫,接著往下看,會(huì)介紹下基本的使用,然后參照其官方文檔,相信可以實(shí)現(xiàn)出大多數(shù)你想要的動(dòng)畫的。
1. ReactCSSTransitionGroupreact-addons-css-transition-group,一般稱其export的組件為ReactCSSTransitionGroup,它提供一種聲明的方式來(lái)定義CSS動(dòng)畫。ReactCSSTransitionGroup的子組件必須大于或等于1個(gè),不能為空。
ReactCSSTranstionGroup組件暴露的屬性有:
transitionAppear/transitionEnter/transitionLeave: Boolean 類型,標(biāo)識(shí)是否開(kāi)啟動(dòng)畫
transitionAppearTimeout/transitionEnterTimeout/transitionLeaveTimeout: 定義各階段動(dòng)畫的時(shí)長(zhǎng)
transitionName:自定義各階段動(dòng)畫的 CSS 樣式名
component: ReactCSSTranstion以什么組件包裹(wrap)子組件,默認(rèn)為span,可以是React Element 。
我們以 todo-list 為例,看看ReactCSSTransitionGroup怎么使用。由于篇幅限制,todo-list 相關(guān)的業(yè)務(wù)代碼忽略,可以在這里查看完整代碼。以下是動(dòng)畫部分代碼:
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 (... ,) } }{ items.map((item)=>( {item})) }
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; }
有兩點(diǎn)需要注意:
每個(gè)子組件必須有key,這樣ReactCSSTrasntionGroup才能正確的mounting和unmounting子組件。
自定義的動(dòng)畫時(shí)長(zhǎng),需要與CSS樣式中定義的動(dòng)畫時(shí)長(zhǎng)對(duì)應(yīng)上。
關(guān)于react-addons-css-transition-group,知乎這篇文章CSS 動(dòng)畫及其在 React 中的應(yīng)用有較為詳細(xì)的介紹。
2. ReactTransitionGroupreact-addons-transition-group是react-addons-css-transition-group的low-level API,其提供動(dòng)畫執(zhí)行中需要的各生命周期函數(shù):
componentWillAppear(): componentDidMount時(shí)執(zhí)行, 渲染TransitionGroup時(shí)執(zhí)行并且只會(huì)執(zhí)行一次。
componentDidAppear(): 傳給componentWillAppear的callback執(zhí)行后執(zhí)行。
componentWillEnter(): componentDidMount時(shí)執(zhí)行,子組件添加進(jìn)TransitionGroup時(shí)執(zhí)行。
componentDidEnter(): 傳給componentWillEnter的callback執(zhí)行后執(zhí)行。
componentWillLeave(): 子組件從TransitionGroup中移除時(shí)執(zhí)行,Though the child has been removed, TransitionGroup will keep it in the DOM until callback is called.
componentDidLeave(): componentWillLeave的callback執(zhí)行后執(zhí)行。通常情況下與ComponentWillUnmount的時(shí)機(jī)一致。
那我們看看,同樣以 todo-list 為例, ReactTransitionGroup需要怎么做呢?
index.js:
import React,{ Component } from "react" ; import ReactTransitionGroup from "react-addons-transition-group" ; class Item extends Component{ // 獲取組件真實(shí)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 ({text}) } } export class App extends Component{ ... , render(){ const { items } = this.state ; return (... ,) } }{ items.map((item,i)=>(- )) }
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,我們需要自己去控制組件的動(dòng)畫生命周期,增加了一定的復(fù)雜度,但是對(duì)自動(dòng)以動(dòng)畫,又能提供更好的靈活度??梢愿鶕?jù)業(yè)務(wù)場(chǎng)景,選擇合適的Group,去實(shí)現(xiàn)我們的需求。
通常情況下,我們用ReactCSSTransitionGroup就能滿足較多的業(yè)務(wù)場(chǎng)景了,并且從實(shí)現(xiàn)上會(huì)容易很多。
3. ReactMotionreact-motion提供了5個(gè)API接口:
spring: 動(dòng)畫生成方法
Motion: React 組件
StaggeredMotion: React 組件
TransitionMotion: React 組件
presets: spring方法的配置項(xiàng)
跟其他React動(dòng)畫庫(kù)一樣,react-motion也提供React組件去包裹需要?jiǎng)赢嫷臉I(yè)務(wù)組件。其中:
Motion組件只接受一個(gè)children組件
StaggeredMotion組件接受一組children組件
TranstionMotion組件可以支持其children組件mounting和unmounting定義動(dòng)畫
仍然是 todo-list 的例子,react-motion的實(shí)現(xiàn)也非常簡(jiǎn)單:
import React,{ Component } from "react" ; import { Motion , spring } from "react-motion"; export default class App extends Component{ ... , render(){ const { items } = this.state ; return (... ,) } }{ items.map((item)=>{ return ({ interpolatingStyle => ( ) }) }{item}) }
通過(guò)上述簡(jiǎn)單的代碼,即可實(shí)現(xiàn)每個(gè)Item在mounting的時(shí)候漸現(xiàn)的效果。
另一方面,觀察上述實(shí)現(xiàn),我們不難發(fā)現(xiàn),react-motion不僅僅支持React web應(yīng)用,它應(yīng)該也能輕松的應(yīng)用到React-Native中。因?yàn)槠銻eact組件只是根據(jù)提供的defaultStyle及style屬性,生成動(dòng)畫的數(shù)據(jù),業(yè)務(wù)應(yīng)用中拿到生成的數(shù)據(jù)后根據(jù)需要添加需要?jiǎng)赢嫷慕M件樣式。react-motion在web應(yīng)用中性能表現(xiàn)較為可觀,在React-Native應(yīng)用中的性能表現(xiàn),有待我們調(diào)研。
除了上述簡(jiǎn)單的動(dòng)畫應(yīng)用,react-motion在復(fù)雜動(dòng)畫的實(shí)現(xiàn)方面,表現(xiàn)非常優(yōu)越。下面的動(dòng)圖是react-motion實(shí)現(xiàn)的一個(gè)動(dòng)畫演示:
這個(gè)示例展示了部分react-motion的能力,更多關(guān)于react-motion的應(yīng)用就讓我們一起去發(fā)現(xiàn)吧。
結(jié)語(yǔ)當(dāng)然React動(dòng)畫相關(guān)的庫(kù)還有很多,本文不過(guò)多介紹。通過(guò)上述對(duì)這些庫(kù)的使用做簡(jiǎn)單介紹,筆者希望通過(guò)對(duì)它們實(shí)現(xiàn)進(jìn)行分析,讓讀者能更好的理解與掌握,能對(duì)React動(dòng)畫的實(shí)現(xiàn)原理和實(shí)現(xiàn)方式,有更為清晰的認(rèn)識(shí)。
但是對(duì)相關(guān)代碼的研究,深入度還不足以給讀者朋友分享,所以暫時(shí)留坑,后續(xù)會(huì)將相關(guān)源碼的學(xué)習(xí),記錄在文檔React動(dòng)畫的實(shí)現(xiàn)原理一文中,并計(jì)劃添加從零開(kāi)始,實(shí)現(xiàn)React動(dòng)畫文章作為學(xué)習(xí)成果。如果對(duì)React動(dòng)畫保有興趣,可以關(guān)注這兩篇文章的后續(xù)內(nèi)容。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/94656.html
摘要:大家可以嘗試使用的,配置一個(gè)合適的勁度系數(shù)和空氣阻力。所做的事,只不過(guò)自己實(shí)現(xiàn)了一套緩動(dòng)函數(shù)。 根據(jù)經(jīng)典力學(xué)的觀點(diǎn),世界上所有的原子每時(shí)每刻仿佛都會(huì)根據(jù)當(dāng)前速度、受力和位置計(jì)算出下一刻的速度、受力和位置。上帝有一臺(tái)超級(jí)計(jì)算機(jī)嗎?非也,反而計(jì)算機(jī)是我們利用原子的這些特性拼裝出來(lái)的?,F(xiàn)在,我們卻要用計(jì)算機(jī),像上帝那樣,再造一個(gè)世界。 我不知道這個(gè)世界上有沒(méi)有仿世學(xué),但是既然動(dòng)畫是要模仿現(xiàn)實(shí)...
摘要:父組件向子組件之間非常常見(jiàn),通過(guò)機(jī)制傳遞即可。我們應(yīng)該聽(tīng)說(shuō)過(guò)高階函數(shù),這種函數(shù)接受函數(shù)作為輸入,或者是輸出一個(gè)函數(shù),比如以及等函數(shù)。在傳遞數(shù)據(jù)的時(shí)候,我們可以用進(jìn)一步提高性能。 本文主要談自己在react學(xué)習(xí)的過(guò)程中總結(jié)出來(lái)的一些經(jīng)驗(yàn)和資源,內(nèi)容邏輯參考了深入react技術(shù)棧一書以及網(wǎng)上的諸多資源,但也并非完全照抄,代碼基本都是自己實(shí)踐,主要為平時(shí)個(gè)人學(xué)習(xí)做一個(gè)總結(jié)和參考。 本文的關(guān)鍵...
摘要:父組件向子組件之間非常常見(jiàn),通過(guò)機(jī)制傳遞即可。我們應(yīng)該聽(tīng)說(shuō)過(guò)高階函數(shù),這種函數(shù)接受函數(shù)作為輸入,或者是輸出一個(gè)函數(shù),比如以及等函數(shù)。在傳遞數(shù)據(jù)的時(shí)候,我們可以用進(jìn)一步提高性能。 本文主要談自己在react學(xué)習(xí)的過(guò)程中總結(jié)出來(lái)的一些經(jīng)驗(yàn)和資源,內(nèi)容邏輯參考了深入react技術(shù)棧一書以及網(wǎng)上的諸多資源,但也并非完全照抄,代碼基本都是自己實(shí)踐,主要為平時(shí)個(gè)人學(xué)習(xí)做一個(gè)總結(jié)和參考。 本文的關(guān)鍵...
摘要:父組件向子組件之間非常常見(jiàn),通過(guò)機(jī)制傳遞即可。我們應(yīng)該聽(tīng)說(shuō)過(guò)高階函數(shù),這種函數(shù)接受函數(shù)作為輸入,或者是輸出一個(gè)函數(shù),比如以及等函數(shù)。在傳遞數(shù)據(jù)的時(shí)候,我們可以用進(jìn)一步提高性能。 本文主要談自己在react學(xué)習(xí)的過(guò)程中總結(jié)出來(lái)的一些經(jīng)驗(yàn)和資源,內(nèi)容邏輯參考了深入react技術(shù)棧一書以及網(wǎng)上的諸多資源,但也并非完全照抄,代碼基本都是自己實(shí)踐,主要為平時(shí)個(gè)人學(xué)習(xí)做一個(gè)總結(jié)和參考。 本文的關(guān)鍵...
摘要:我模仿的應(yīng)用構(gòu)建了一個(gè)開(kāi)閉卡片的輪播效果作為技術(shù)演示它使用了及其動(dòng)畫庫(kù)當(dāng)人們聽(tīng)到后第一反應(yīng)會(huì)覺(jué)得它運(yùn)行緩慢這是因?yàn)橐话闳藭?huì)去這樣解釋它允許你通過(guò)構(gòu)建你的應(yīng)用程序而人們會(huì)認(rèn)為瀏覽器中運(yùn)行的性能并不夠好但事實(shí)是它采用的全部都是原生界面元素但你通 我模仿 Facebook 的 Paper 應(yīng)用構(gòu)建了一個(gè)開(kāi)閉卡片的輪播效果作為技術(shù)演示.它使用了 React Native 及其動(dòng)畫庫(kù). 當(dāng)人們聽(tīng)...
閱讀 2310·2023-04-25 14:22
閱讀 3748·2021-11-15 18:12
閱讀 1303·2019-08-30 15:44
閱讀 3224·2019-08-29 15:37
閱讀 653·2019-08-29 13:49
閱讀 3466·2019-08-26 12:11
閱讀 887·2019-08-23 18:28
閱讀 1592·2019-08-23 14:55