(32)React 拓展——② 使用 react-transition-group 实现动画 | React 基础理论实操

复制代码
转载请注明出处,未经同意,不可修改文章内容。

🔥🔥🔥"前端一万小时"两大明星专栏------"从零基础到轻松就业"、"前端面试刷题",已于本月大改版,合二为一,干货满满,欢迎点击公众号菜单栏各模块了解。

1 CSSTransition

紧接上一篇代码,本篇我们用 React 动画的第三方模块 react-transition-group 来轻松实现更加复杂的动画效果。

1️⃣安装这个模块:

css 复制代码
npm install react-transition-group --save

2️⃣本节我们主要讲解 CSSTransition 的使用(Transition 是更底层的组件,当 CSSTransition 实现不了我们的需求时,可以去查查 Transition 的 API。而 TransitionGroup 的话,我们会在下一节讲解!),跟着官方文档的"例子"进行操作:

打开 App.js 文件:

javascript 复制代码
import React, { Component, Fragment } from "react";  

// 2️⃣-①:引入 CSSTransition 动画组件;
import { CSSTransition } from 'react-transition-group';  

import "./style.css";

class App extends Component  {
  constructor(props) { 
    super(props);
    
    this.state = {
      show: true  
    }
    
    this.handleBtnToggle = this.handleBtnToggle.bind(this); 
  }
  
  render() {
    return (
      <Fragment>
      
        {/*
         ❗️❗️❗️2️⃣-②:有了 CSSTransition 后,我们就不需要自己去进行样式的添加和移除了!
        <div className={this.state.show ? "show" : "hide"}>hello, qdywxs.</div>
          */}
      
        {/*
         2️⃣-③:取而代之,我只需要在 div 元素的外层嵌套一个 CSSTransition 组件即可。
         CSSTransition 会自动帮我们做一些 class 的增加、移除的工作;
          */}
        <CSSTransition>
          <div>hello, qdywxs.</div>
			  </CSSTransition>
 
        <button onClick={this.handleBtnToggle}>toggle</button>
      </Fragment>
    );
  }
  
  handleBtnToggle() {
    this.setState({
      show: this.state.show ? false : true
    })
  }
}

export default App;

❗️❗️❗️2️⃣-④:接着需要对 CSSTransition 做一些设置;

🚀在具体的代码编写之前,我们先熟悉一下基本的理论知识:

1. CSSTransition 组件中重要的 API 解析
  • in :Boolean,控制组件显示与隐藏。 true 显示, false 隐藏;

  • timeout :Number,延迟,涉及到动画状态的持续时间。可传入一个对象,如 {exit: 300, enter: 500} 来分别设置" 入"和"离开"的延时;

  • classNames :String,动画进行时给元素添加的类名。一般利用这个属性来设计动画!(❗️特别注意:是 classNames 而不是 className !)

  • unmountOnExit :Boolean,这是一个很实用的 API,它为我们节省了很多精力。为 true 时------组件为隐藏状态时移除组件;为 false 时------组件保持动画结束时的状态而不移除元素(一般要设成 true )。

2. 类名的添加

动画进行时,以 classNames="fade" 为例,CSSTransition 将自动依次为要执行动画的元素添加以下类名:

  • fade-enter

  • fade-enter-active

  • fade-enter-done

  • fade-exit

  • fade-exit-active

  • fade-exit-done

我们也可以单独指定每一个类名:

javascript 复制代码
classNames={{
	enter: "my-enter",
  enterActive: "my-active-enter",
  enterDone: "my-done-enter",
  
  exit: "my-exit",
  exitActive: "my-active-exit",
  exitDone: "my-done-exit"
}}
3. 每个类名的添加时机
  • enter :当元素进入时添加;

  • enter-active :当元素进入到页面后添加。它与 enter 的主要差别是------ enter-active 是在元素已经添加到页面后才会添加 enter-active ,而 enter 在元素添加到页面时已经携带;

  • enter-done :动画执行完毕后添加。动画时长取决于 timeout

  • exit :元素离开时添加。离开动画时长取决于 timeout

  • exit-active :同 exit

  • exit-done :离开动画完成后添加(仅在 unmountOnExitfalse 时有效)。

2️⃣-⑤:基础理论知识介绍完后,我们直奔 App.js 文件进行代码的编写;

jsx 复制代码
import React, { Component, Fragment } from "react";  

import { CSSTransition } from 'react-transition-group';  

import "./style.css";

class App extends Component  {
  constructor(props) { 
    super(props);
    
    this.state = {
      show: true  
    }
    
    this.handleBtnToggle = this.handleBtnToggle.bind(this); 
  }
  
  render() {
    return (
      <Fragment>
      
      	{/* ❗️2️⃣-⑥:对 CSSTransition 进行设置; */}
        <CSSTransition
          in={this.state.show}
      		timeout={1000}
  				classNames="fade"
					unmountOnExit={true}
        >
            
          <div>hello, qdywxs.</div>
			  </CSSTransition>
 
        <button onClick={this.handleBtnToggle}>toggle</button>
      </Fragment>
    );
  }
  
  handleBtnToggle() {
    this.setState({
      show: this.state.show ? false : true
    })
  }
}

export default App;

❗️❗️❗️2️⃣-⑦:打开 style.css 文件(清空之前的代码),我们在里边定义动画"进行时"各阶段的效果(🏆CSSTransition 已自动为我们添加了动画各阶段对应的 class ,我们只需要给各 class 添加对应的效果即可);

css 复制代码
.fade-enter {
  opacity: 0;
}
.fade-enter-active {
  opacity: 1;
  transition: opacity 1s ease-in;
}
fade-enter-done {
  opacity: 1;
}

.fade-exit {
  opacity: 1;
}
.fade-exit-active {
  opacity: 0;
  transition: opacity 1s ease-in;
}
fade-exit-done {
  opacity: 0;
}

返回页面查看效果:

3️⃣我们继续查阅官方文档,拉到最下边,官方为我们提供了很多"钩子函数 "。"钩子函数"是什么?它是会在适当的时候自动执行的函数!

利用这些"钩子函数",我们就可以用 JS 来控制一些样式 了。如(打开 App.js 文件):

javascript 复制代码
import React, { Component, Fragment } from "react";  

import { CSSTransition } from 'react-transition-group';  

import "./style.css";

class App extends Component  {
  constructor(props) { 
    super(props);
    
    this.state = {
      show: true  
    }
    
    this.handleBtnToggle = this.handleBtnToggle.bind(this); 
  }
  
  render() {
    return (
      <Fragment>

        {/*
         ❗️❗️❗️在这里定义一个"钩子函数",当"入场动画"结束之后,
         onEntered 自动执行!
         ❗️里边的参数 el 指的就是 CSSTransition 内部包裹的这个 div 元素!
          */}
        <CSSTransition
          in={this.state.show}
          timeout={1000}
          classNames="fade"
          unmountOnExit={true}

          onEntered={(el) => {
            el.innerHTML="hello, 前端一万小时.";
            el.style.color="red";
          }}
        >  
            
          <div>hello, qdywxs.</div>
        </CSSTransition>
 
        <button onClick={this.handleBtnToggle}>toggle</button>
      </Fragment>
    );
  }
  
  handleBtnToggle() {
    this.setState({
      show: this.state.show ? false : true
    })
  }
}

export default App;

返回页面查看效果:

❓4️⃣上边的动画效果有个问题:页面初次打开时(刷新页面),动画效果是不执行的!怎样解决这个问题呢?

答:CSSTransition 的 appear 属性可以帮助我们实现------页面一打开,动画效果就生效!

打开 App.js 文件:

javascript 复制代码
import React, { Component, Fragment } from "react";  

import { CSSTransition } from 'react-transition-group';  

import "./style.css";

class App extends Component  {
  constructor(props) { 
    super(props);
    
    this.state = {
      show: true  
    }
    
    this.handleBtnToggle = this.handleBtnToggle.bind(this); 
  }
  
  render() {
    return (
      <Fragment>

        {/* ❗️4️⃣-①:增加一个 appear 属性; */}
        <CSSTransition
          in={this.state.show}
          timeout={1000}
          classNames="fade"
          unmountOnExit={true}

					appear={true}

          onEntered={(el) => {
            el.innerHTML="hello, 前端一万小时.";
            el.style.color="red";

          }}
        >  
            
          <div>hello, qdywxs.</div>
        </CSSTransition>
 
        <button onClick={this.handleBtnToggle}>toggle</button>
      </Fragment>
    );
  }
  
  handleBtnToggle() {
    this.setState({
      show: this.state.show ? false : true
    })
  }
}

export default App;

4️⃣-②:当用了 appear 属性后,CSSTransition 会帮助我们干一件事------它会在入场动画的第一帧增加一个名为 fade-appearclass ;还会在整个动画进行过程中增加一个名为 fade-appear-activeclass

打开 style.css 文件:

css 复制代码
.fade-enter, .fade-appear { /* ❗️增加 fade-appear */
  opacity: 0;
}
.fade-enter-active, .fade-appear-active { /* ❗️增加 fade-appear-active */
  opacity: 1;
  transition: opacity 1s ease-in;
}
fade-enter-done {
  opacity: 1;
}

.fade-exit {
  opacity: 1;
}
.fade-exit-active {
  opacity: 0;
  transition: opacity 1s ease-in;
}
fade-exit-done {
  opacity: 0;
}

返回页面查看效果:

2 TransitionGroup

Transition Group 可以帮助我们实现多个元素的动画效果。

❓需求:紧接上边的代码,当我每点击一次 toggle 按钮时,页面都会相应显示一行 hello, qdywxs. 。且,显示的时候都会有动画效果(入场动画结束后,会变成红色的 hello, 前端一万小时. )。 答:

1️⃣打开 App.js 文件(将里边的代码清空),我们先来实现"点击" --> "显示"的逻辑:

jsx 复制代码
import React, { Component, Fragment } from "react";  

import "./style.css";

class App extends Component  {
  constructor(props) { 
    super(props);
    
    this.state = {
      list:[]
    }
    
    this.handleAddItem = this.handleAddItem.bind(this); 
  }
  
  render() {
    return (
      <Fragment>

        {
          this.state.list.map((item, index) => {
            return (
              <div key={index}>hello, qdywxs.</div>
            )
          })
        }

        <button onClick={this.handleAddItem}>toggle</button>

      </Fragment>
    );
  }
  
  handleAddItem() {
    this.setState((prevState) => {
      return {
        list: [...prevState.list, "item"]
      }
    })
  }
}

export default App;

看下页面效果:

2️⃣实现每一项 hello, qdywxs. 出现时,都有动画效果(请对照 TransitionGroup 官方文档学习并自行拓展):

javascript 复制代码
import React, { Component, Fragment } from "react";  

// 2️⃣-①:引入 CSSTransition 和 TransitionGroup 这两个"组件";
import {
  CSSTransition,
  TransitionGroup,
} from "react-transition-group";

import "./style.css";

class App extends Component  {
  constructor(props) { 
    super(props);
    
    this.state = {
      list:[]
    }
    
    this.handleAddItem = this.handleAddItem.bind(this); 
  }
  
  render() {
    return (
      // 2️⃣-②:参照官方文档例子,给要添加动画的"多个元素"的最外层包裹一个 TransitionGroup 标签;
      /*
      2️⃣-③:给单个元素包裹 CSSTransition 标签(这个和上文讲的做法一模一样,
      可以直接拷贝过来,❗️但要去掉属性 in);
       */
      <Fragment>
        <TransitionGroup>
          {
            this.state.list.map((item, index) => {
              return (
                <CSSTransition
                  timeout={1000}
                  classNames="fade"
                  unmountOnExit={true}

                  appear={true}

                  onEntered={(el) => {
                    el.innerHTML="hello, 前端一万小时.";
                    el.style.color="red";
                  
                  }} 
                  
                  key={index}
                >
                  <div>hello, qdywxs.</div>
                </CSSTransition>
              )
            })
          }
        </TransitionGroup>

        <button onClick={this.handleAddItem}>toggle</button>

      </Fragment>
    );
  }
  
  handleAddItem() {
    this.setState((prevState) => {
      return {
        list: [...prevState.list, "item"]
      }
    })
  }
}

export default App;

返回页面查看效果:

祝好,qdywxs ♥ you!

相关推荐
崔庆才丨静觅2 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60612 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了2 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅3 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅3 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅3 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment3 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅4 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊4 小时前
jwt介绍
前端
爱敲代码的小鱼4 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax