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 组件上。


以上。

相关推荐
kyriewen1 小时前
别再 console.log 了:5 个 Chrome DevTools 调试技巧,用过就回不去了
前端·javascript·面试
IT_陈寒3 小时前
Python搞不定字符串编码?这破玩意坑我两小时!
前端·人工智能·后端
To_OC3 小时前
LC 1 两数之和:面试第一道必考题,暴力解法直接被面试官 pass
javascript·算法·leetcode
DigitalOcean4 小时前
Laravel 开发者已在 DigitalOcean 上开通超过 10 万台服务器
前端·laravel
星始流年4 小时前
从 Tool 到 Skill——基于 LangChain 的服务端Skill实现
前端·langchain·agent
李惟5 小时前
开源本地通信库,纯客户端 RPC,像聊天一样通信
前端
YAwu115 小时前
深入解析 React 炫彩鼠标跟随标题组件:从坐标定位到动画性能
前端·react.js
GuWenyue5 小时前
排序效率低?5分钟吃透快速排序,性能飙升至O(nlogn)
前端·javascript·面试
OpenTiny社区5 小时前
🎨 看完 GenUI SDK 源码我悟了!
前端·vue.js·github
叁两5 小时前
前端转型AI Agent该如何学习?(前置篇)
前端·人工智能·node.js