• React@16.x(33)动画(上)


    使用 react-transition-group 来实现动画。总共有4个动画组件,覆盖大多应用场景。

    1,Transition

    官方文档

    过渡动画的原理,和 Vue的过渡动画 类似。分为2个阶段:

    1. 进入(enter)过渡动画,对应的状态有3个,
      1. 进入前的初始状态 default
      2. 动画进行中的状态 entering
      3. 进入后的结束状态 entered
    2. 退出(exit / leave)过渡动画,对应的状态也是3个,
      1. 退出前的初始状态 entered
      2. exiting
      3. exited

    注意
    进入前的初始状态和 exited 是一个状态。
    退出前的初始状态和 entered 也是一个状态。

    以一个渐入渐出动画举例,

    .default {
    	transition: opacity 2s ease-in-out;
    }
    .default, .exiting, .exited{
    	opacity: 0;
    }
    .entering, .entered {
    	opacity: 1;
    }
    

    官方文档的例子:

    import { Transition } from "react-transition-group";
    import { useRef, useState } from "react";
    
    // 过渡时间
    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 },
    };
    
    /**
     * Transition.children 是一个函数,函数的返回值是要进行动画的元素。
     * 函数会随着过渡动画的进行而调用(进入动画会调用3次,对应3种状态),参数 state 就是当前过渡状态。
     * @param {in} boolean,动画开关。从 false-> true,开启进入动画,反之退出动画。
     * @returns
     */
    function Fade({ in: inProp }) {
        const nodeRef = useRef(null);
        return (
            <Transition
                nodeRef={nodeRef}
                in={inProp}
                timeout={duration}
                addEndListener={() => {
                    nodeRef.current.addEventListener(
                        "transitionend",
                        () => {
                            console.log("过渡结束");
                        },
                        { once: true }
                    );
                }}
            >
                {(state) => (
                    <div
                        ref={nodeRef}
                        style={{
                            ...defaultStyle,
                            ...transitionStyles[state],
                        }}
                    >
                        I'm a fade Transition!
                    </div>
                )}
            </Transition>
        );
    }
    
    export default function App() {
        const [visible, setVisible] = useState(true);
        return (
            <>
                <button
                    onClick={() => {
                        setVisible(!visible);
                    }}
                >
                    切换动画
                </button>
                <Fade in={visible} />
            </>
        );
    }
    

    效果:

    在这里插入图片描述

    也可以不用内联样式,而用 class 来添加更多的样式:

    <div className={state}>I'm a fade Transition!div>
    

    一些常用 props

    1,mountOnEnter

    延迟挂载。顾名思义,在进入动画开始前再加载要进行动画的元素。默认 false 立即加载。

    比如,对渐入渐出动画来说,如果初始值 in={false},也就是说元素一开始是隐藏的。

    • 默认情况下 mountOnEnter={false} 元素依然会被挂载到 DOM 中,等待动画开始。
    • 如果设置 mountOnEntermountOnEnter={true} 则元素延迟挂载,一开始并不会挂载到DOM中,直到动画开始才挂载并进行动画。

    2,unmountOnExit

    顾名思义,在退出动画结果后,是否在DOM中直接卸载动画元素。默认 false 不卸载。

    3,appear

    默认情况下,在元素挂载阶段,如果 in={true} 则直接进入动画的最终状态,整个过程 Transition.children 只会调用一次,参数 state=entered

    此时设置 appearappear={true},则进入动画会经历完整3个阶段,函数也会运行 3 次。

    注意,Transition 组件中并没有提供 appear 这个状态,所以也无法设置改状态下的样式。所以只是函数会运行3次而已
    如果想一开始就执行一次进入的过渡动画,得使用下面这个组件 CSSTransition

    还有其他的一些属性不多介绍了,比如设置过渡动画结束后的回调函数等。用到时参考官方文档即可。

    2,CSSTransition

    官方文档

    2.1,和 Transition 组件的区别

    1. CSSTransition 是在 Transition 的基础上实现的,可以理解为是它的增强版,同时继承了它的所有属性 props。
    2. Transition 只是提供了基础的进入和退出动画,并将过渡状态 state 暴露出来,通过它来设置样式。更复杂的动画需要用到 onEnter 等回调函数来实现。
      CSSTransition 是基于 CSS 的过渡动画组件,只需要为不同的过渡状态指定相应的类名(classNames),CSSTransition 会自动在适当的时机添加或删除这些类。
    3. CSSTransition* 能够实现加载动画

    2.2,举例

    import { CSSTransition } from "react-transition-group";
    import { useState } from "react";
    import "./App.css";
    
    export default function App() {
        const [inProp, setInProp] = useState(true);
        return (
            <div>
                <CSSTransition in={inProp} timeout={200} classNames="crane">
                    <div>classNames 是自定义类名前缀</div>
                </CSSTransition>
                <button type="button" onClick={() => setInProp(!inProp)}>
                    进入/退出
                </button>
            </div>
        );
    }
    
    .crane-enter {
        opacity: 0;
    }
    .crane-enter-active {
        opacity: 1;
        transition: opacity 200ms;
    }
    .crane-enter-done {
        opacity: 1;
    }
    .crane-exit {
        opacity: 1;
    }
    .crane-exit-active {
        opacity: 0;
        transition: opacity 200ms;
    }
    
    .crane-exit-done {
        opacity: 0;
    }
    

    逻辑,动画效果和 Transition 组件差不多。同样的,进入和退出动画分别有3种状态,不过直接对应到类名上了:

    • 进入动画
      1. enter,动画开始前的初始化类名。
      2. enter-active,动画进行中的类名。
      3. enter-done,动画结束后的类名。
    • 退出动画
      1. exit
      2. exit-active
      3. exit-done
    • 还多了加载动画
      1. appear
      2. appear-active
      3. appear-done

    2.3,常用 props

    2.3.1,classNames

    有2种情况:

    • 字符串,表示动画类名前缀(上面的例子已经演示了)。
    • 对象,设置状态对应的动画类名(所以可结合 animate.css 使用,下文有举例)。
    classNames={{
     appear: 'my-appear',
     appearActive: 'my-active-appear',
     appearDone: 'my-done-appear',
     enter: 'my-enter',
     enterActive: 'my-active-enter',
     enterDone: 'my-done-enter',
     exit: 'my-exit',
     exitActive: 'my-active-exit',
     exitDone: 'my-done-exit',
    }}
    

    2.3.2,appear

    Transition 组件的 appear 属性中,介绍了它没有对应的状态来设置样式。而 CSSTransition 组件是有的。

    举例:(只包含关键代码)

    <CSSTransition in={true} appear classNames="crane">CSSTransition>
    
    .crane-appear {
        transform: translateX(200px);
    }
    .crane-appear-active {
        transform: translateX(0);
        transition: transform 200ms;
    }
    .crane-appear-done {
        transform: translateX(0);
    }
    

    这样,在页面加载完成时(刷新页面后),就会执行上面的动画了。

    2.4,结合 animate.css

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

    安装:

    npm install animate.css -S
    

    样例完整代码:

    import { CSSTransition } from "react-transition-group";
    import { useRef, useState } from "react";
    import "./App.css";
    import "animate.css";
    
    function MyCSSTransition({ in: inProp, children }) {
        return (
            <div>
                <CSSTransition
                    in={inProp}
                    appear
                    mountOnEnter
                    timeout={1000}
                    classNames={{
                        appearActive: "animate__fadeInRight",
                        enterActive: "animate__fadeInRight",
                        exitActive: "animate__fadeOutLeft",
                        exitDone: "exit-done",
                    }}
                >
                    <div className="animate__animated common">
                        {children}
                    </div>
                </CSSTransition>
            </div>
        );
    }
    
    export default function App() {
        const [inProp, setInProp] = useState(true);
        return (
            <div className="app-box">
                <MyCSSTransition in={inProp}>
                    <h1>组件1</h1>
                </MyCSSTransition>
                <MyCSSTransition in={!inProp}>
                    <h1>组件2</h1>
                </MyCSSTransition>
                <button type="button" onClick={() => setInProp(!inProp)}>
                    进入/退出
                </button>
            </div>
        );
    }
    
    /* App.css */
    .app-box {
        position: relative;
        margin-left: 80px;
        padding-top: 100px;
        width: 200px;
    }
    .common {
        position: absolute;
        top: 0;
    }
    
    .exit-done {
        display: none;
    }
    

    效果:

    在这里插入图片描述

    注意点:

    1,在引入 animate.css 后,对要进行动画的元素的添加基础类名animate__animated,其他过渡动画添加 animate__动画类名即可。比如:

    <h1 class="animate__animated animate__bounce">An animated elementh1>
    

    2,classNames 属性的类名最终会添加到 ref={nodeRef} 的元素上。

    3,因为 animate.css 中的类名都是过渡动画的类名,所以只需要设置 appearActiveenterActiveexitActive这3个进行中的状态类名+最终态类名即可。

    4,注意也设置了 mountOnEnter 属性,这是为了让没有进行动画的元素先不加载,以免影响到进行加载动画 appearActive 的元素。

    接下篇文章 React 动画(下)


    以上。

  • 相关阅读:
    物联网AI MicroPython传感器学习 之 Relay继电器模块
    流水的数字内容,铁打的内容风控
    数据湖iceberg-day01-概念,特点,存储格式以及各种表中的演化,数据类型
    Azides-PEG-PLGA 叠氮-聚乙二醇-聚乳酸-羟基乙酸共聚物 的参数信息
    2024年山东省职业院校技能大赛中职组“网络安全”赛项竞赛试题-C
    QT--线程
    Pod详解
    记录帖 ES的RestApi使用
    spring框架源码十四、源码剖析注意事项及容器初始化主体流程
    【ElasticSearch】使用 Java 客户端 RestClient 实现对文档的查询操作,以及对搜索结果的排序、分页、高亮处理
  • 原文地址:https://blog.csdn.net/qq_40147756/article/details/139638456