React@16.x(34)动画(中)

目录

接上面文章 React动画(上)

3,SwitchTransition

官方文档

在上篇文章中,用 CSSTransition 做了一个动画:

可以看到,这2个元素的动画是同时发生的,因为使用同一个状态变量控制的(代码参考上篇文章)

SwitchTransition 组件是专门用来做切换动画 的,并且2个元素的动画是有先后顺序的。

元素1完成退出动画后,元素2再开始进入动画。

3.1,原理

默认情况下(mode="out-in"),通过改变状态变量来改变 key 值,才能开始切换动画,

key 属性替换了之前的 in 属性。

如果默认 state=true,渲染元素1,则切换状态时的动画过程:

  1. 先给元素1添加类名 exit exit-active,元素1执行退出动画。
  2. 等元素1的退出动画完成(过渡时间结束),再给元素2添加类名 enter enter-active 执行进入动画。
  3. 等元素2的进入动画完成,类名切换为 enter-done

所以,只需要设置这5个类名对应的样式即可。

如果进入动画结束后,用的默认样式(比如: opacity: 1)那类名 enter-done 也不用设置。

3.1.2,key

因为会将退出动画和进入动画对应的类名,设置到对应的元素上,来实现切换动画。

所以如果不设置,那所有的类名会加到同一个元素上,结果是该元素无限进入循环动画(退出-进入-退出...)

key 只要保证唯一,能区分为2个元素即可。

3.1.2,mode

默认 out-in,具体动画过程上面已经介绍了。

in-out,如果默认 state=true,渲染元素1,则切换状态时的动画过程:

  1. 保持元素1不变,为元素2添加enter enter-active 执行进入动画。
  2. 过渡时间结束,元素2的类名变为 enter-done,同时为元素1添加类名 exit exit-active,开始退出动画。
  3. 过渡时间结束,元素1被移除。

相当于先执行了一次元素2的进入动画,之后再开始执行元素1的退出动画。

3.2,举例

js 复制代码
import { CSSTransition, SwitchTransition } from "react-transition-group";
import { useRef, useState } from "react";
import "./App.css";

export default function App() {
    const [state, setState] = useState(true);
    return (
        <SwitchTransition>
            <CSSTransition key={state} timeout={500}>
                <button onClick={() => setState(!state)}>{state ? "状态1" : "状态2"}</button>
            </CSSTransition>
        </SwitchTransition>
    );
}
css 复制代码
/* App.css */
.enter {
    opacity: 0;
}
.enter-active {
    opacity: 1;
    transition: opacity 1s;
}

.exit {
    opacity: 1;
}
.exit-active {
    opacity: 0;
    transition: opacity 1s;
}

效果:

同样的,要在过渡完成后执行 transitionend 事件,可以:

js 复制代码
export default function App() {
    const [state, setState] = useState(true);
    const refBtn1 = useRef(null);
    const refBtn2 = useRef(null);
    const nodeRef = state ? refBtn1 : refBtn2;
    return (
        <SwitchTransition>
            <CSSTransition
                key={state}
                timeout={1000}
                nodeRef={nodeRef}
                addEndListener={() => {
                    nodeRef.current.addEventListener(
                        "transitionend",
                        () => {
                            console.log("过渡结束");
                        },
                        { once: true }
                    );
                }}
            >
                <button ref={nodeRef} onClick={() => setState((state) => !state)}>
                    {state ? "状态1" : "状态2"}
                </button>
            </CSSTransition>
        </SwitchTransition>
    );
}

3.3,结合 animate.css

animate 样式举例1animate 样式举例2

安装:

bash 复制代码
npm install animate.css -S

样例完整代码:

js 复制代码
import { CSSTransition, SwitchTransition } from "react-transition-group";
import { useState } from "react";
import "animate.css";

export default function App() {
    const [state, setState] = useState(true);
    return (
        <SwitchTransition>
            <CSSTransition
                key={state}
                timeout={1000}
                classNames={{
                    appearActive: "animate__fadeInRight",
                    enterActive: "animate__fadeInRight",
                    exitActive: "animate__fadeOutLeft",
                }}
            >
                <button className="animate__animated" onClick={() => setState(!state)}>
                    {state ? "状态1" : "状态2"}
                </button>
            </CSSTransition>
        </SwitchTransition>
    );
}

效果:

4,TransitionGroup

官方文档

它接收一组 CSSTransitionTransition,统一控制它们的进入和退出动画。

SwitchTransition 一样,会添加对应的类名来实现动画。

经典例子:待办列表,可以动态新增或删除待办项,同时为每一项都应用动画。

js 复制代码
import { TransitionGroup, CSSTransition } from "react-transition-group";
import { useState } from "react";
import { v4 as uuidv4 } from "uuid";
import "./App.css";

export default function App() {
    const [todoList, setTodoList] = useState([
        { id: uuidv4(), content: "学习" },
        { id: uuidv4(), content: "吃饭" },
        { id: uuidv4(), content: "睡觉" },
    ]);
    return (
        <>
            <TransitionGroup>
                {todoList.map((item) => (
                    <CSSTransition key={item.id} timeout={500}>
                        <div>
                            <span>{item.content}</span>
                            <button
                                onClick={() => {
                                    const resultItem = todoList.filter((f) => f.id !== item.id);
                                    setTodoList(resultItem);
                                }}
                            >
                                删除
                            </button>
                        </div>
                    </CSSTransition>
                ))}
            </TransitionGroup>
            <button
                onClick={() => {
                    const answer = window.prompt();
                    setTodoList([
                        ...todoList,
                        {
                            id: uuidv4(),
                            content: answer,
                        },
                    ]);
                }}
            >
                新增
            </button>
        </>
    );
}

4.1,其他属性

4.1.2,appear

统一添加加载动画,同时会有 appearappear-activeappear-done 类名。

4.1.2,component

控制渲染的容器的节点类名,默认 divnull 表示不渲染节点。

html 复制代码
<TransitionGroup appear component="ul">

4.1.3,classNames

component 对应节点的类名,不是动画类名前缀。

动画类名前缀,还是要添加到 CSSTransition 组件上。


以上。

相关推荐
abc800211703424 分钟前
前端Bug 修复手册
前端·bug
Best_Liu~27 分钟前
el-table实现固定列,及解决固定列导致部分滚动条无法拖动的问题
前端·javascript·vue.js
_斯洛伐克1 小时前
下降npm版本
前端·vue.js
苏十八2 小时前
前端进阶:Vue.js
前端·javascript·vue.js·前端框架·npm·node.js·ecmascript
st紫月3 小时前
用MySQL+node+vue做一个学生信息管理系统(四):制作增加、删除、修改的组件和对应的路由
前端·vue.js·mysql
乐容3 小时前
vue3使用pinia中的actions,需要调用接口的话
前端·javascript·vue.js
似水明俊德4 小时前
ASP.NET Core Blazor 5:Blazor表单和数据
java·前端·javascript·html·asp.net
至天5 小时前
UniApp 中 Web/H5 正确使用反向代理解决跨域问题
前端·uni-app·vue3·vue2·vite·反向代理
与墨学长5 小时前
Rust破界:前端革新与Vite重构的深度透视(中)
开发语言·前端·rust·前端框架·wasm
H-J-L6 小时前
Web基础与HTTP协议
前端·http·php