首页 > 其他分享 >想给组件加上进入离开动画?试试 react-transition-group

想给组件加上进入离开动画?试试 react-transition-group

时间:2024-01-15 11:31:46浏览次数:30  
标签:动画 group transition react className enter active

列表是很常见的场景:

想给组件加上进入离开动画?试试 react-transition-group_JavaScript

如果我们想给它加上进入离开的动画效果:

想给组件加上进入离开动画?试试 react-transition-group_JavaScript_02

怎么做呢?

一般我们会用 react-transition-group 来做。

在 npm 官网可以看到,这个包每周有 750w 下载量,还是非常流行的:

想给组件加上进入离开动画?试试 react-transition-group_JavaScript_03

那这个包怎么用呢?

我们写下代码试一下:

npx create-react-app transition-group-test

想给组件加上进入离开动画?试试 react-transition-group_React.js_04

用 create-react-app 创建个项目。

把它跑起来:

npm run start

想给组件加上进入离开动画?试试 react-transition-group_App_05

安装 react-transition-group:

npm install --save react-transition-group

先不着急用,先想想如果有一个 div,如何给它加上进入离开的动画效果呢?

import './App.css';

function App() {

  return (
    <div id="box">
    </div>
  );
}

export default App;
#box {
  width: 300px;
  height: 50px;
  background: lightblue;
  margin: 200px auto;
}

这样一个 div:

想给组件加上进入离开动画?试试 react-transition-group_JavaScript_06

改变 translate 就可以让它动起来:

import { useEffect, useState } from 'react';
import './App.css';

function App() {
  const [style, setStyle] = useState({
    transform: 'translateX(-100%)'
  }, []);

  useEffect(() => {
    setTimeout(() => {
      setStyle({ transform: 'translateX(0%)' })
    }, 1000);
  })

  return (
    <div id="box" style={style}>
    </div>
  );
}

export default App;

想给组件加上进入离开动画?试试 react-transition-group_JavaScript_07

加上 transition,让它慢慢的动:

想给组件加上进入离开动画?试试 react-transition-group_React.js_08

想给组件加上进入离开动画?试试 react-transition-group_ci_09

然后再加个透明度变化:

想给组件加上进入离开动画?试试 react-transition-group_ci_10

想给组件加上进入离开动画?试试 react-transition-group_JavaScript_11

这样,进入的效果就完成了。

也就是说,设置 transtion 之后,只要改变 transform 和 opacity 就行了。

当然,我么也可以把这俩 style 封装到 className 里,然后增删 className 就行。

也就是这样:

想给组件加上进入离开动画?试试 react-transition-group_App_12

import { useEffect, useState } from 'react';
import './App.css';

function App() {
  const [className, setClassname] = useState('');

  useEffect(() => {
    setClassname('enter');

    setTimeout(() => {
      setClassname('enter-active');
    });
  }, []);

  return (
    <div id="box" className={className}>
    </div>
  );
}

export default App;

效果和之前一样:

想给组件加上进入离开动画?试试 react-transition-group_ci_13

可以看到,className 变了,导致样式改变,触发 transition 动画:

想给组件加上进入离开动画?试试 react-transition-group_App_14

我们还可以在 transition 结束的时候,再添加一个 className:

想给组件加上进入离开动画?试试 react-transition-group_前端_15

.enter-done {
  border: 5px solid #000;
}

想给组件加上进入离开动画?试试 react-transition-group_JavaScript_16

可以看到,最开始 className 是 enter,后来切换到 enter-active,触发了 transition 动画,最后动画结束切换到了 enter-done。

react-transition-group 也是通过改变 className 来给组件加上的过渡效果。

我们试一下:

import { useEffect, useState } from 'react';
import { CSSTransition } from 'react-transition-group';
import './App.css';

function App() {
  const [flag, setFlag] = useState(false);

  useEffect(() => {
    setTimeout(() => {
      setFlag(true);
    }, 3000);
  }, []);

  return <CSSTransition
    in={flag}
    timeout={1000}
  >
    <div id="box"></div>
  </CSSTransition>
}

export default App;
#box {
  width: 300px;
  height: 50px;
  background: lightblue;
  margin: 200px auto;
}

.enter {
  transform: translateX(-100%);
  opacity: 0;
}

.enter-active {
  transform: translateX(0);
  opacity: 1;

  transition: all 1s ease;
}

.enter-done {
  border: 5px solid #000;
}

样式部分没有变化,还是 enter、enter-active、enter-done 这 3 个。

现在就不用自己改 className了,用 CSSTransition 组件,它会自己给加这些 className。

参数 in 设置为 true 就是触发进入的动画,设置为 false 就是触发离开的动画。

想给组件加上进入离开动画?试试 react-transition-group_ci_17

看起来 enter 和 enter-active 好像是同时设置的,其实不是。

CSSTransition 组件会先设置 enter,再设置 enter-active,这样就触发动画了。

然后到了 timeout 参数的时间,就会设置 enter-done 的 className。

反之,如果 in 的参数改为 false,就会触发离开动画:

想给组件加上进入离开动画?试试 react-transition-group_JavaScript_18

className 会先设置 exit,再设置 exit-active 来触发动画,到了 timeout 的时间会设置为 exit-done。

连起来,就可以实现 enter 和 exit 的动画:

import { useEffect, useState } from 'react';
import { CSSTransition } from 'react-transition-group';
import './App.css';

function App() {
  const [flag, setFlag] = useState(false);

  return <div>
    <CSSTransition
      in={flag}
      timeout={1000}
    >
      <div id="box"></div>
    </CSSTransition>
    <button onClick={() => setFlag(!flag)}>{!flag ?  '进入' : '离开'}</button>
  </div>
}

export default App;
#box {
  width: 300px;
  height: 50px;
  background: lightblue;
  margin: 100px auto;
}

button {
  margin: 0 auto;
  display: block;
}

.enter {
  transform: translateX(-100%);
  opacity: 0;
}

.enter-active {
  transform: translateX(0);
  opacity: 1;

  transition: all 1s ease;
}

.enter-done {
  border: 5px solid #000;
}

.exit {
  transform: translateX(0%);
  opacity: 1;
}

.exit-active {
  transform: translateX(100%);
  opacity: 0;

  transition: all 1s ease;
}

.exit-done {
}

想给组件加上进入离开动画?试试 react-transition-group_React.js_19

可以看到,通过 className 从 enter 到 enter-active 到 enter-done 的变化,以及从 exit 到 exit-active 到 exit-done 的变化,就实现了进入和离开的动画。

不知道大家有没有发现,最开始出现的时候是没有动画的,之后后来切换 in 的 props 的时候,才有动画。

如果想最开始出现的时候就做一次动画呢?

这就需要设置 appear 的 props 了:

想给组件加上进入离开动画?试试 react-transition-group_App_20

.appear {
  transform: scale(0);
}

.appear-active {
  transform: scale(1);
  transition: all 1s ease;
}

.appear-done {

}

想给组件加上进入离开动画?试试 react-transition-group_React.js_21

可以看到,最开始还有一个 appear、appear-active、appear-done 的 className 变化,并且还会添加 enter-done。

这个只会在刚出现的时候设置一次。

也就是一共可以有 appear、enter、exit 3 种动画。

现在是我们自己设置 in 的 props 来触发进入和离开动画的,如果是列表的多个 child,都想加动画呢?

这时候就用 TransitionGrop 组件。

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

export default function App() {
  const [items, setItems] = useState([
    { id: 1, text: "guang" },
    { id: 2, text: "guang" },
  ]);

  return (
    <div>
      <TransitionGroup className="item-box">
        {items.map(({ id, text }) => (
          <CSSTransition key={id} timeout={1000}>
            <div className="item">
              <span
                className="del-btn"
                onClick={() => {
                  setItems(items.filter((item) => item.id !== id));
                }}
              >
                x
              </span>
              {text}
            </div>
          </CSSTransition>
        ))}
      </TransitionGroup>

      <div
        className="btn"
        onClick={() => {
          setItems([...items, { id: Date.now(), text:  'guang' }]);
        }}
      >
        Add
      </div>
    </div>
  );
}

就是用 TransitionGroup 包裹下,

.item-box {
  width: 300px;
  margin: 20px auto;
}

.item {
  margin: 4px 0;
  padding: 10px 0;
  border-radius: 4px;
  background: lightblue;
}

.del-btn {
  padding: 0 10px;
  cursor: pointer;
  user-select: none;
}

.enter {
  opacity: 0;
  transform: translateX(-100%);
  background: lightblue;
}
.enter-active {
  opacity: 1;
  transform: translateX(0%);
  background: lightblue;
  transition: all 1s ease;

}
.enter-done {
}
.exit {
  opacity: 1;
  transform: translateX(0%);
  background: red;
}
.exit-active {
  opacity: 0;
  transform: translateX(100%);
  background: red;
  transition: all 1s ease;
}

.btn {
  color: #fff;
  background-color: #0069d9;
  border-color: #0062cc;
  padding: 10px 20px;
  border-radius: 4px;
  width: fit-content;
  cursor: pointer;
  margin: 20px auto;
}

效果就是文章开头看到的那个:

想给组件加上进入离开动画?试试 react-transition-group_React.js_22

用 CSSTransition 的时候,我们需要自己设置 in 的 props 来触发进入和离开动画。

而现在 TransitionGroup 会在 children 变化的时候对比新旧 item,来自动设置 in,触发动画。

这就是 react-transition-group 的常用功能。

此外,它还有两个组件,Transition 和 SwitchTransition:

把 CSSTransition 换成 Transition,然后打印下 status:

想给组件加上进入离开动画?试试 react-transition-group_React.js_23

可以看到,status 最开始是从 entering 到 entered,从 exiting 到 exited 变化,但是不会设置 className:

想给组件加上进入离开动画?试试 react-transition-group_JavaScript_24

我们可以根据 status 的变化自己设置 className。

其实,CSSTransition 就是基于 Transition 封装的。

一般我们用 CSSTransition 就好了。

再就是 SwithTransition,先看下效果:

想给组件加上进入离开动画?试试 react-transition-group_ci_25

包裹一层 SwitchTransition,然后设置下 key。

当 mode 为 in-out 时:

想给组件加上进入离开动画?试试 react-transition-group_React.js_26

当 mode 为 out-in 时:

想给组件加上进入离开动画?试试 react-transition-group_React.js_27

这个组件就是用来控制两个组件切换时的进入、离开动画的顺序的。

这样,react-transition-group 的 4 个组件: Transition、CSSTransition、TransitionGroup、SwitchTransition 我们就都过了一遍。

那它是怎么实现的呢?

react-transition-group 还是用 class 的方式写的,我们简单看一下就行:

首先,Transition 组件会设置一个 status 的状态,根据 in 和 appear 参数来决定初始值。

想给组件加上进入离开动画?试试 react-transition-group_JavaScript_28

然后 in 参数变化的时候,会修改 status:

想给组件加上进入离开动画?试试 react-transition-group_JavaScript_29

比如 enter 的时候,会先修改 status 为 entering,然后触发 onEntering 回调,之后修改 status 为 entered,然后触发 onEntered 回调:

想给组件加上进入离开动画?试试 react-transition-group_ci_30

CSSTransition 就是在这些回调里设置 className 的:

想给组件加上进入离开动画?试试 react-transition-group_ci_31

其实也很简单,就是 status 变化,触发回调,回调函数里修改 className。

而 TransitionGroup 则是会在 children 变化的时候,对比下新旧 children,决定如何设置 in 的 props,也就是触发进入离开动画:

想给组件加上进入离开动画?试试 react-transition-group_App_32

还有 SwitchTransition 组件,这个就是根据 mode 的设置,确定是先触发旧 children 的 exit,然后在 onExited 回调里触发新 children 的 enter,还是反过来:

想给组件加上进入离开动画?试试 react-transition-group_React.js_33

综上,Transition 组件是核心,而 CSSTransition、SwitchTransition、TransitionGroup 都是在它基础上封装的。

这就是 react-transition-group 的实现原理。

总结

当我们想给一个列表的列表项加上进入离开的动画的时候,可以用 react-trasition-group 这个包。

它是 react 官方出的,非常流行的一个包。

常用来做这种效果:

想给组件加上进入离开动画?试试 react-transition-group_前端_34

它有 Transition、CSSTransition、TransitionGroup、SwitchTransition 这 4 个组件。

Transition 会通过 in 和 appear 的 props 来设置 status,并且在 props 变化的时候修改 status,触发不同的回调。

CSSTransition 就是在这些回调里实现了 className 的修改:

  • 进入的时候会触发 enter、enter-active、enter-done 的 className 切换
  • 离开的时候是 exit、exit-active、exit-done 的切换
  • 如果设置了 appear 参数,刚出现的时候,还会有 appear、appear-active、appear-done 的切换。

不过如果是列表,那不用自己设置 in 的 props,直接用 TransitionGroup 包一层就行。

SwitchTransition 则是用来控制两个组件切换的时候,先进入再离开,还是先离开再进入。

它们的实现原理并不复杂,就是 in 的 props 触发 status 变化,而 status 变化会触发回调函数,在回调里实现 className 的修改。

当你需要进入、离开的过渡动画的时候,react-transition-group 还是很好用的。

标签:动画,group,transition,react,className,enter,active
From: https://blog.51cto.com/u_15506823/9251347

相关文章

  • DIANN-MSstats groupComparison Issue: undefined columns selected
    1.Whaterrormessagedidyouencounter?Errorin`[.data.frame`(as.data.frame(comparisons),,cols):undefinedcolumnsselected 2.Howdidyousolvetheerror?install.packages("lme4",type="source") 3.Whatarethepos......
  • React 系列 useImperativeHandle
    ReactHooks为我们提供了一种全新的方式来处理组件的状态和生命周期。其中,useImperativeHandle 是一个相对较少被提及的Hook,但在某些场景下,它是非常有用的。本文将深入探讨 useImperativeHandle 的用法,并通过实例来加深理解。什么是 useImperativeHandle?useImperativeHandle......
  • React-hook-form-mui(一):基本使用
    前言在项目开发中,我们选择了React+MUI作为技术栈。在使用MUI构建form表单时,我们发现并没有与antd类似的表单验证功能,于是我们选择了MUI推荐使用的react-hook-form-mui库去进行验证。但是发现网上关于这个库的使用方法和demo比较少且比较简单,并没有复杂的表单验证的demo。因此本文及......
  • React 详解(1)
    React简介React基础JSX的本质JSX并不是标准的JS语法,它是JS的语法扩展,浏览器本身不能识别,需要通过解析工具做解析之后才能在浏览器中运行。这里主要依靠BABEL解析工具来解析,下面简单的介绍一下这个解析工具(http://babeljs.io):JSX中使用JS表达式在JSX中可以通过大括号语法......
  • 多种 React 组件通信方式实践
    使用ReactContext基于ReactContext实现跨组件通信的一个常见用例是创建一个能够在不同组件间共享和触发行为的上下文。以下是一个简化的例子,展示了如何在app.tsx中触发其他组件(例如,一个弹窗组件)中的方法。1.创建一个Context首先,我们创建一个新的Context。这个Context将......
  • 【flink番外篇】9、Flink Table API 支持的操作示例(13)- Row-based(map、flatmap、aggre
    文章目录Flink系列文章一、maven依赖二、Row-based操作1、本示例的公共代码1、Map2、FlatMap3、Aggregate4、GroupWindowAggregate5、FlatAggregate本文介绍了通过TableAPI基于行的map、flatmap、aggregate、groupwindowaggregate和flataggregate操作,并以示例进行展示操......
  • 【flink番外篇】9、Flink Table API 支持的操作示例(11)- Group Windows(tumbling、slidi
    文章目录Flink系列文章一、maven依赖二、Groupwindow1、Tumble(TumblingWindows)2、Slide(SlidingWindows)3、Session(SessionWindows)本文介绍了表的groupwindows三种窗口(tumbling、sliding和session)操作,以示例形式展示每个操作的结果。本文除了maven依赖外,没有其他依......
  • 【flink番外篇】9、Flink Table API 支持的操作示例(6)- 表的聚合(group by、Distinct、
    文章目录Flink系列文章一、maven依赖二、示例:表的聚合操作1、示例代码公共部分2、groupby3、GroupByWindowAggregation4、OverWindowAggregation5、DistinctAggregation6、Distinct本文给出了关于表数据的聚合操作示例,比如groupby、distinct、以及groupby、over、distin......
  • 2024-01-13 Can't perform a React state update on an unmounted component. This i
    react+antd业务代码报错: Can'tperformaReactstateupdateonanunmountedcomponent.Thisisano-op,butitindicatesamemoryleakinyourapplication.Tofix,cancelallsubscriptionsandasynchronoustasksinauseEffectcleanupfunction.无法对未安装的......
  • pm2启动react项目总是stopped
    执行命令pm2start--name服务名npm--start总是不成功status一直显示stopped使用命令pm2logs查看日志报错如下网上查看这篇教程解决问题原文:https://blog.csdn.net/qq_52912134/article/details/127262835现在项目里面下载一个node-cmdnpminstallnode-cmd--save......