【譯】只需四個步驟:使用 React 實現頁面過渡動畫

翻譯:瘋狂的技術宅
做者:Martin Haagensli
英文標題:Animated page transitions with React Router 4, ReactTransitionGroup and Animated
英文地址:https://hackernoon.com/animat...
說明:本文首發於公衆號:jingchengyidengjavascript

clipboard.png

在本文中,我將向你展現如何使用 ReactTransitionGroup 和 Animated 庫中的生命週期方法來實現頁面的過渡效果。css

你能夠經過這個視頻 http://animate.mhaagens.me 來觀看演示效果。html

讓咱們看看該怎樣設置一些簡單的路由動畫!java

一、安裝React

首先安裝 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

二、添加 React 路由

打開 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 />中。

首先把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()

讓咱們用它們來製做一個更高級的組件來實現個人的動畫路由效果,如今好戲開場了!

四、建立Animated Wrapper 並用 Animated 實現動畫

建立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


歡迎掃描二維碼關注公衆號,天天第一時間推送我翻譯的國外最新技術文章。

相關文章
相關標籤/搜索