翻譯:瘋狂的技術宅
做者:Martin Haagensli
英文標題:Animated page transitions with React Router 4, ReactTransitionGroup and Animated
英文地址:https://hackernoon.com/animat...
說明:本文首發於公衆號:jingchengyidengjavascript
在本文中,我將向你展現如何使用 ReactTransitionGroup 和 Animated 庫中的生命週期方法來實現頁面的過渡效果。css
你能夠經過這個視頻 http://animate.mhaagens.me 來觀看演示效果。html
讓咱們看看該怎樣設置一些簡單的路由動畫!java
首先安裝 React 並建立一個 React 應用程序,很簡單的就能建立一個 React 項目並讓它運行。react
若是你尚未安裝 Create React App 就先裝好(若是你已經安裝,就跳過這一步):git
npm install -g create-react-app
而後建立咱們的項目:github
create-react-app animatedroutes && cd animatedroutes
接下來安裝 routes 和 animation 包:spring
yarn add react-router-dom animated react-transition-group
如今用你喜歡的編輯器打開項目,並運行它:npm
npm start
打開 src/index.js
文件,給 React 添加 BrowserRoutersegmentfault
import React from "react"; import ReactDOM from "react-dom"; import { BrowserRouter } from "react-router-dom"; import App from "./App"; import registerServiceWorker from "./registerServiceWorker"; import "./index.css"; ReactDOM.render( <BrowserRouter> <App /> </BrowserRouter>, document.getElementById("root") ); registerServiceWorker();
而後添加兩個須要渲染的組建,首先是 src/Home.js
:
import React, { Component } from "react"; export default class Home extends Component { render() { return ( <div className="page"> <h1>Home</h1> <p>Hello from the home page!</p> </div> ) } }
接着是 src/Subpage.js
:
import React, { Component } from "react"; export default class Subpage extends Component { render() { return ( <div className="page"> <h1>Subpage</h1> <p>Hello from a sub page!</p> </div> ) } }
下面打開src/App.js
文件並修改內容爲:
import React, { Component } from 'react'; import { Route, Link } from "react-router-dom"; import Home from "./Home"; import Subpage from "./Subpage"; class App extends Component { render() { return ( <div className="App"> <div className="TopBar"> <Link to="/">Home</Link> <Link to="/subpage">Subpage</Link> </div> <Route exact path="/" component={Home} /> <Route exact path="/subpage" component={Subpage} /> </div> ); } } export default App;
最後刪除 src/App.css
的內容,並把下面的代碼複製到src/index.css
文件中:
html, body, #root { height: 100%; width: 100%; } body { margin: 0; padding: 0; font-family: sans-serif; } .App { position: relative; display: flex; flex-flow: column; } .TopBar { position: fixed; top: 0; left: 0; display: flex; flex-flow: row nowrap; align-items: center; width: 100%; height: 62px; padding: 0 24px; } .TopBar a { margin-right: 18px; text-decoration: none; } .animated-page-wrapper { position: absolute; top: 62px; left: 0; width: 100%; height: 100%; } .page { padding: 0 24px; }
好了,如今能夠經過路由在主頁面和子頁面之間進行導航了。
如今開始添加動畫效果。咱們須要作一些微不足道的工做來實現它。
如今,咱們再也不用默認的方式設置路由,而是要使用路由渲染方法來去渲染前面的組件,並將其封裝到一個<TransitionGroup />
中。
首先把TransitionGroup導入你的 src/App.js
,像這樣:
import TransitionGroup from "react-transition-group/TransitionGroup";
而後咱們必須爲 TransitionGroup 添加一個特殊的函數來渲染子組件。在 src/App.js
文件中class App extends ...
的前面添加這個函數:
const firstChild = props => { const childrenArray = React.Children.toArray(props.children); return childrenArray[0] || null; };
而後刪除你的路由,並替換成下面的代碼:
<Route exact path="/" children={({ match, ...rest }) => ( <TransitionGroup component={firstChild}> {match && <Home {...rest} />} </TransitionGroup> )}/> <Route path="/subpage" children={({ match, ...rest }) => ( <TransitionGroup component={firstChild}> {match && <Subpage {...rest} />} </TransitionGroup> )}/>
您如今能夠訪問新的生命週期方法了,好比 componentWillAppear()
,componentWillEnter()
和componentWillLeave()
。
讓咱們用它們來製做一個更高級的組件來實現個人的動畫路由效果,如今好戲開場了!
建立src/AnimatedWrapper.js
文件並複製下面的代碼到文件中:
import React, { Component } from "react"; import * as Animated from "animated/lib/targets/react-dom"; const AnimatedWrapper = WrappedComponent => class AnimatedWrapper extends Component { constructor(props) { super(props); this.state = { animate: new Animated.Value(0) }; } render() { return ( <Animated.div className="animated-page-wrapper"> <WrappedComponent {...this.props} /> </Animated.div> ); } }; export default AnimatedWrapper;
這裏有不少東西,我來解釋一下。
咱們用component來包裝咱們的路由組件。它將從 TransitionGroup 接收生命週期方法,咱們能夠用它來實現動畫效果。
咱們還用 Animated 建立了一個變量,能夠用它來對封裝的子組件中的 div 的不一樣樣式屬性實現動畫效果。
讓咱們添加一些生命週期方法給組件添加動畫效果。用Animated.template
渲染,而且/或者插入動畫狀態值。
按照下面的代碼修改src/AnimatedWrapper.js
文件內容:
import React, { Component } from "react"; import * as Animated from "animated/lib/targets/react-dom"; const AnimatedWrapper = WrappedComponent => class AnimatedWrapper extends Component { constructor(props) { super(props); this.state = { animate: new Animated.Value(0) }; } componentWillAppear(cb) { Animated.spring(this.state.animate, { toValue: 1 }).start(); cb(); } componentWillEnter(cb) { setTimeout( () => Animated.spring(this.state.animate, { toValue: 1 }).start(), 250 ); cb(); } componentWillLeave(cb) { Animated.spring(this.state.animate, { toValue: 0 }).start(); setTimeout(() => cb(), 175); } render() { const style = { opacity: Animated.template`${this.state.animate}`, transform: Animated.template` translate3d(0,${this.state.animate.interpolate({ inputRange: [0, 1], outputRange: ["12px", "0px"] })},0) ` }; return ( <Animated.div style={style} className="animated-page-wrapper"> <WrappedComponent {...this.props} /> </Animated.div> ); } }; export default AnimatedWrapper;
而後咱們須要在每一個路由組件中導入它,而後像這樣將它們封裝起來:
修改 src/Home.js
以下:
import React, { Component } from "react"; import AnimatedWrapper from "./AnimatedWrapper"; class HomeComponent extends Component { render() { return ( <div className="page"> <h1>Home</h1> <p>Hello from the home page!</p> </div> ) } } const Home = AnimatedWrapper(HomeComponent); export default Home;
修改 src/Subpage.js
以下:
import React, { Component } from "react"; import AnimatedWrapper from "./AnimatedWrapper"; class SubpageComponent extends Component { render() { return ( <div className="page"> <h1>Subpage</h1> <p>Hello from a sub page!</p> </div> ) } } const Subpage = AnimatedWrapper(SubpageComponent); export default Subpage;
就這樣,如今你的頁面切換效果應該是動態的了!
我建議經過Animated文檔來學習,可是如今相關文檔不多。咱們實用的Animated.template
函數在 Github-issues 之外的地方几乎找不到。它的文檔在這裏:http://animatedjs.github.io/i...。
你能夠經過下面的連接下載Demo的演示視頻:
http://animate.mhaagens.me/
或者:
https://github.com/mhaagens/a...
也能夠關注我在Medium的博客或者個人Twitter,來學習更多 React 相關的內容。
https://twitter.com/mhaagens
歡迎掃描二維碼關注公衆號,天天第一時間推送我翻譯的國外最新技術文章。