【译】只需四个步骤:使用 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


欢迎扫描二维码关注公众号,天天第一时间推送我翻译的国外最新技术文章。

相关文章
相关标签/搜索