react-transition-group 探究(二)

238 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第22天,点击查看活动详情

用法可以参考这个:www.jianshu.com/p/49fa164b9…

其实和第一章的类似

文档:reactcommunity.org/react-trans…

它建立在 Transition 组件之上,因此它继承了它的所有 props。

CSSTransition 在过渡的出现、进入和退出状态期间应用一对类名。

The animation classNames applied to the component as it appears, enters, exits or has finished the transition. A single name can be provided, which will be suffixed for each stage, e.g. classNames="fade" applies:

在组件出现、进入、退出或完成过渡时应用于组件的动画类名。可以提供一个名称,每个阶段都会加上后缀,例如classNames="fade" 适用

  • fade-appear, fade-appear-active, fade-appear-done
  • fade-enter, fade-enter-active, fade-enter-done
  • fade-exit, fade-exit-active, fade-exit-done

例子

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

const duration = 1030;
// 动画 样式

function App() {
  const [inProp, setInProp] = useState(false);
  return (
    <div className="App">
      <header className="App-header">
        {/* in 显示组件;触发进入或退出状态,默认false。 timeout 动画时间 */}
        <CSSTransition in={inProp} timeout={duration} classNames="fade"    
            onEnter={() => console.log("onEnter")}>
          {(state) => <div>I'm a fade Transition!</div>}
        </CSSTransition>
        <button onClick={() => setInProp(!inProp)}>Click to Enter</button>
      </header>
    </div>
  );
}

export default App;

# test.css
.fade-enter {
  opacity: 0;
}
.fade-enter-active {
  opacity: 1;
  transition: opacity 200ms;
}
.fade-enter-done {
  opacity: 1;
}
.fade-exit {
  opacity: 1;
}
.fade-exit-active {
  opacity: 0;
  transition: opacity 200ms;
}
.fade-exit-done {
  opacity: 0;
}

初始的时候没有类,intrue后,赋予了fade-enterfade-enter-active,动画时间后变成fade-enter-done

truefalseenter变成exit

动画的状态就是从fade-enter变成fade-enter-active

还有六个属性

onEnter
onEntering
onEntered
onExit
onExiting
onExited

onEnter:A <Transition> callback fired immediately after the 'enter' or 'appear' class is applied.

Note: when nodeRef prop is passed, node is not passed.

type: Function(node: HtmlElement, isAppearing: bool)

原理:

当元素进入动画时 调用 该回调,参数的元素。

调用 onEnter时,要去掉 exit相关的类,添加 enter 类。

调用 onEntering,添加 entering

调用 onEntered ,去掉 前面两个类,添加onEntered

源码实现

  • 该组件是在 Transition基础上实现的,先继承过来
import {Transition} from './Transition';
function CSSTransition(props) {
    // 获取动画类名
    function getClassNames(status) {
        const { classNames } = props;
        return {
            // fade-enter, fade-enter-active, fade-enter-done
            base: `${classNames}-${status}`, // 基础样式
            active: `${classNames}-${status}-active`,//动画样式
            done: `${classNames}-${status}-done`
        }
    }
  function onEnter(node) {
    // 获取动画结束的类,并去掉,添加动画开始的类名
    const exitClassNames = Object.values(getClassNames("exit")); // ['fade-exit', 'fade-exit-active', 'fade-exit-done']
    removeClass(node, exitClassNames);
    const enterClassName = getClassNames("enter").base; // ['fade-enter', 'fade-enter-active', 'fade-enter-done']
    addClass(node, enterClassName);

    props?.onEnter(node); // 回调函数
  }
    return (
        <Transition onEnter={onEnter} in={props.in} timeout={props.timeout}>
            {props.children}
        </Transition>
    )
}
function removeClass(node, classes) {
  //  移除样式
  (Array.isArray(classes) ? classes : [classes]).forEach((cls) =>
    node.classList.remove(cls)
  );
}
//  添加样式
function addClass(node, classes) {
  (Array.isArray(classes) ? classes : [classes]).forEach((cls) =>
    node.classList.add(cls)
  );
}
export { CSSTransition }
  • Transition里 完成 onEnter等属性的插入
    performEnter = () => {
      const { timeout, onEnter, onEntering, onEntered } = this.props
        const node = ReactDom.findDOMNode(this)
        onEnter?.(node)
        this.setState({
            status: ENTERING
        }, () => {
            onEntering?.(node)
            this.onTransitionEnd(timeout, () => {
                this.setState({ status: ENTERED })
                onEntered?.(node)
            })
        })
    }

完整源码

import { Transition } from "./Transition";

function CSSTransition(props) {
  // 获取动画类名
  function getClassNames(status) {
    const { classNames } = props;
    return {
      // fade-enter, fade-enter-active, fade-enter-done
      base: `${classNames}-${status}`, // 基础样式
      active: `${classNames}-${status}-active`, //动画样式
      done: `${classNames}-${status}-done`,
    };
  }
  function onEnter(node) {
    // 获取动画结束的类,并去掉,添加动画开始的类名
    const exitClassNames = Object.values(getClassNames("exit")); // ['fade-exit', 'fade-exit-active', 'fade-exit-done']
    removeClass(node, exitClassNames);
    const enterClassName = getClassNames("enter").base; // ['fade-enter', 'fade-enter-active', 'fade-enter-done']
    addClass(node, enterClassName);

    props?.onEnter(node); // 回调函数
  }
  function onEntering(node) {
    const enterClassName = getClassNames("enter").active; // ['fade-enter', 'fade-enter-active', 'fade-enter-done']
    addClass(node, enterClassName);
  }
  function onEntered(node) {
    const { base, active, done } = getClassNames("enter");
    removeClass(node, [base, active]);
    addClass(node, done);
  }
  function onExit(node) {
    // 获取动画结束的类,并去掉,添加动画开始的类名
    const exitClassNames = Object.values(getClassNames("enter")); // ['fade-exit', 'fade-exit-active', 'fade-exit-done']
    removeClass(node, exitClassNames);
    const enterClassName = getClassNames("exit").base; // ['fade-enter', 'fade-enter-active', 'fade-enter-done']
    addClass(node, enterClassName);
  }
  function onExiting(node) {
    const enterClassName = getClassNames("exit").active; // ['fade-enter', 'fade-enter-active', 'fade-enter-done']
    addClass(node, enterClassName);
  }
  function onExited(node) {
    const { base, active, done } = getClassNames("exit");
    removeClass(node, [base, active]);
    addClass(node, done);
  }

  return (
    <Transition
      onEnter={onEnter}
      onEntering={onEntering}
      onEntered={onEntered}
      onExit={onExit}
      onExiting={onExiting}
      onExited={onExited}
      in={props.in}
      timeout={props.timeout}
    >
      {props.children}
    </Transition>
  );
}
function removeClass(node, classes) {
  //  移除样式
  (Array.isArray(classes) ? classes : [classes]).forEach((cls) =>
    node.classList.remove(cls)
  );
}
//  添加样式
function addClass(node, classes) {
  (Array.isArray(classes) ? classes : [classes]).forEach((cls) =>
    node.classList.add(cls)
  );
}
export { CSSTransition };