React使用动画

我们在开发中可以使用一些动画来控制组件消失和隐藏的过渡动画,增加用户交互的体验。

React社区提供了一个库react-transition-group来完成过渡动画。使用网址参考

安装方式:

//npm
npm install react-transition-group -S
//yarn 
yarn add react-transition-group -D

这个库可以帮助我们实现组件的入场和离场动画,实际上就是为组件添加类名,根据不同的时刻,我们可以就此来设置过渡动画。

该库体积很小,主要包含四个组件:TransitionCSSTransitionSwitchTransitionTransitionGroup

Transition

该组件是一个与平台无关的组件,不一定要结合css,如果要结合css可以使用CSSTransition
这个组件常用于组件的挂载和卸载的过渡动画,该组件默认情况下Transition组件不会改变它呈现的组件的行为,它只跟踪组件的enterexit状态。这取决于你赋予的状态效果。例如,当组件进入或退出时,我们可以向它添加style样式,以下是一个案例:

import React, { PureComponent } from "react";
import { Transition } from "react-transition-group";

const duration = 300;
const defaultStyle = {
  transition: `opacity ${duration}ms ease-in-out`,
  opacity: 0,
};
const transitionStyles = {
  entering: { opacity: 1 },
  entered: { opacity: 1 },
  exiting: { opacity: 0 },
  exited: { opacity: 0 },
};

export default class transitionDemo extends PureComponent {
  render() {
    return (
      <Transition in={this.props.in} timeout={duration}>
        {(state) => (
          <div
            style={{
              ...defaultStyle,
              ...transitionStyles[state],
            }}
          >
            I'm a fade Transition!
          </div>
        )}
      </Transition>
    );
  }
}
import React, { useState } from "react";
import CSSTransitionDemo from "./CSSTransitionDemo";
import SwitchTransitionDemo from "./SwitchTransitionDemo";
import TransitionGroupDemo from "./TransitionGroupDemo";
import TransitionDemo from "./transitionDemo";

function App() {
  const [show, setShow] = useState(false);
  return (
    <div className="App">
      <TransitionDemo in={show} timeout={500} />
      <button onClick={(e) => setShow(!show)}>点击隐藏</button>
    </div>
  );
}
export default App;

我们可以控制in的值来控制为组件赋予状态

首先我们初始化in的值为false,那么组件内容默认不会显示,即处于exited状态,那么style设置的样式透明为0,就不会显示。当我们点击按钮,组件进入entering状态,当500ms(timeout)后组件处于entered状态。

再次点击按钮组件处于exiting状态,延时之后组件就回归exited状态了。

本质上就是在不同的状态添加不同的style样式。

CSSTransition

该组件在组件切换的不同时刻为组件添加类名,我们可以按照这些类名来给组件添加动画。

该组件在执行的额过程中有三个状态,分别为:appearenterexit

每个状态对应一组类名:

  • appear状态: -appear-enter-exit
  • enter状态:-appear-active-enter-active-exit-active
  • exit状态:-appear-done-enter-done-exit-done

组件常用的属性

in 触发进入或者退出状态。
当为true的时候组件触发进入状态,会为组件添加class类名 -enter-enter-acitve,动画结束后移除之前的两个class,并添加-enter-done类名。
当为false的时候组件触发离开状态,会为组件添加-exit-exit-active这两个类名,当动画结束时移除这两个类名,添加类名-exit-done

className动画class类名的前缀。
决定了在编写css时,对应的class名称:比如card-entercard-enter-activecard-enter-done
class类这个属性变化存在的时间是按照time来设置的,反正最好保证和css的动画时间一致

timeout
过渡动画的时间,决定了执行动画时对应类名的存在时间。

appear
该属性决定了是否在第一次进入时添加动画,需要一开始的intrue,即页面刷新和第一次加载进入时就会执行动画,也是添加对应的类。

unmountOnExit
退出动画结束后是否卸载组件,该值默认为false

还有常见的钩子函数等。

案例演示:

import React, { PureComponent } from "react";
import { CSSTransition } from "react-transition-group";
import "./csstransition.css";

export default class CSSTransitionDemo extends PureComponent {
  constructor(props) {
    super(props);
    this.state = {
      isShow: true,
    };
  }
  render() {
    return (
      <div>
        <CSSTransition
          appear
          unmountOnExit={false}
          in={this.state.isShow}
          classNames="card"
          timeout={300}
          onEnter={el=>{console.log('开始状态')}}
          onEntering={el=>{console.log('进入状态')}}
        >
          <div>
            <h2>哈哈啊</h2>
            <h2>哈哈啊</h2>
            <h2>哈哈啊</h2>
            <h2>哈哈啊</h2>
          </div>
        </CSSTransition>
        <button
          onClick={(e) => {
            this.setState({ isShow: !this.state.isShow });
          }}
        >
          显示/隐藏
        </button>
      </div>
    );
  }
}
.card-enter, .card-appear {
  opacity: 0;
}
.card-enter-active,.card-appear-active {
  opacity: 1;
  transition: opacity 300ms;
}
/*  显示动画结束*/
/* .card-enter-done. card-appear-done {
} */

.card-exit {
  opacity: 1;
  transform: scale(1);
}

.card-exit-active {
  opacity: 0;
  transform: scale(0.8);
  transition: opacity 300ms,transform 300ms;
}
.card-exit-done {
  opacity: 0;
  transform: scale(0.6);
}
import CSSTransitionDemo from "./CSSTransitionDemo";

function App() {
  const [show, setShow] = useState(false);
  return (
    <div className="App">
      <CSSTransitionDemo />
    </div>
  );
}

export default App;

SwitchTransition

该组件可以完成两个组件切换时的动画显示。

常用属性
mode
两个值:in-out表示新组件先进来,旧组件再移除。out-in表示旧组件先移除,新组件再进入。

注意:
SwitchTransition组件里面要有CSSTransition或者Transition组件,不能直接包裹你想要切换的组件

SwitchTransition里面的CSSTransitionTransition组件不再像以前那样接受in属性来判断元素是何种状态,取而代之的是key属性,保证不同状态的 key不同即可。

案例展示:

import React, { PureComponent } from "react";
import "./switchtransition.css";
import { SwitchTransition, CSSTransition } from "react-transition-group";
export default class SwitchTransitionDemo extends PureComponent {
  state = { isOn: true };
  render() {
    /* 关于为什么要设置time属性,动画执行的时间是按照css设置的,
    而class类这个属性变化存在的时间是按照time来设置的,反正最好保证这两个时间一致 */
    return (
      <div style={{ textAlign: "center" }}>
        <hr></hr>
        <SwitchTransition mode="out-in">
          <CSSTransition
            key={this.state.isOn ? "on" : "off"}
            classNames="btn"
            timeout={300}
          >
            <button
              onClick={(e) => {
                this.setState({ isOn: !this.state.isOn });
              }}
            >
              {this.state.isOn ? "on" : "off"}
            </button>
          </CSSTransition>
        </SwitchTransition>
      </div>
    );
  }
}
.btn-enter {
  opacity: 0;
  transform: translateX(100%);
}

.btn-enter-active {
  opacity: 1;
  transform: translateX(0);
  transition: opacity 300ms, transform 300ms;
}

.btn-exit {
  transform: translateX(0);
  opacity: 1;
}
.btn-exit-active {
  opacity: 0;
  transform: translateX(-100%);
  transition: opacity 300ms,transform 300ms;
}
import SwitchTransitionDemo from "./SwitchTransitionDemo";

function App() {
  return (
    <div className="App">
      <SwitchTransitionDemo />
    </div>
  );
}
export default App;

TransitionGroup

当我们有一组动画要执行的时候可以使用该组件,比如一个列表增删时的过渡动画。

案例展示:

import React, { PureComponent } from "react";
import { TransitionGroup, CSSTransition } from "react-transition-group";
import "./transitiongroup.css";

export default class TransitionGroupDemo extends PureComponent {
  state = {
    arr: ["zhangsan", "lisi", "wan"],
  };
  render() {
    return (
      <div>
       
          <button onClick={(e) => this.addArr()}>添加</button>
          <ul>
          <TransitionGroup>
            {this.state.arr.map((item, index) => {
              return (
                <CSSTransition key={index} timeout={500} classNames="item">
                  <li>{item}</li>
                </CSSTransition>
              );
            })}
            </TransitionGroup>
          </ul>

      </div>
    );
  }
  addArr() {
    this.setState({
      arr: [...this.state.arr, "haha"],
    });
  }
}
.item-enter {
  opacity: 0;
}
.item-enter-active {
  opacity: 1;
  transition: opacity 500ms;
}
/*  显示动画结束*/
.item-enter-done {
}

.item-exit {
  opacity: 1;
}

.item-exit-active {
  opacity: 0;
  transition: opacity 500ms;
}
.item-exit-done {
  opacity: 0;
}
import TransitionGroupDemo from "./TransitionGroupDemo";

function App() {
  return (
    <div className="App">
      <TransitionGroupDemo />
    </div>
  );
}
export default App;

目前到这里就结束了,这些动画只是基本使用,可以配合上一些动画第三库来食用更佳。

Last modification:March 7, 2022
如果觉得我的文章对你有用,请随意赞赏