1. 动画组件

原理: 利用transition和class类的切换执行transition的动画效果

import React, { useEffect } from "react";
import _ from "lodash";

interface IProps {
  name: string;
  children: React.ReactNode;
  transitionShow: boolean;
}
sessionStorage.transitionObject = JSON.stringify({});
const MyTransition = (props: IProps) => {
  const { name, children, transitionShow } = props;
  const popClass = React.useRef<any>(
    JSON.parse(sessionStorage.transitionObject)
  );

  function orignalSetItem(key, newValue) {
    sessionStorage.setItem(key, newValue);
    // var setItemEvent:any = new Event("setItemEvent");
    // setItemEvent['newValue'] = newValue;
    // window.dispatchEvent(setItemEvent);
  }

  const showTransition = (name, transitionShow = true) => {
    const val = transitionShow ? "-leave-active" : "-leave-to";
    let obj = JSON.parse(sessionStorage.transitionObject) || {};
    obj[name] = name + val;
    for (let key in obj) {
      obj[key] = key + val;
    }
    orignalSetItem("transitionObject", JSON.stringify(obj));
  };

  const getTransition = (name, transitionShow = true) => {
    const val = transitionShow ? "-leave-active" : "-leave-to";
    popClass.current[name] = val;
    let obj = JSON.parse(sessionStorage.transitionObject) || {};
    obj[name] = name + val;
    for (let key in obj) {
      obj[key] = key + val;
      popClass.current[key] = key + val;
    }
    return _.get(obj, name);
  };

  useEffect(() => {
    showTransition(name, transitionShow);
  }, [transitionShow]);

  return <div className={getTransition(name, transitionShow)}>{children}</div>;
};

export default MyTransition;

scss部分:

// transition动画部分
  .myOpacity-enter,
  .myOpacity-leave-to {
    opacity: 0;
  }

  .myOpacity-enter-active,
  .myOpacity-leave-active {
    transition: all 0.5s ease;
  }

  .myPopup-enter,
  .myPopup-leave-to {
    transform: translateY(100px);
  }

  .myPopup-enter-active,
  .myPopup-leave-active {
    transition: all 0.5s ease;
  }

使用方法, 比如一个modal组件需要动画的话:

import React, { useEffect, useState, ReactNode, useImperativeHandle, forwardRef } from "react";
import _ from "lodash";
import "./Picker.scss";
import * as ReactDOM from "react-dom";
import MyTransition from "./MyTransition";

interface IProps {
  isShow: boolean;
  setIsShow: (arg1: boolean) => void;
  children: ReactNode;
}

const MyPickerModal = forwardRef((props: IProps, ref) => {
  const { isShow, setIsShow, children } = props; // 解构props, 得到需要使用来自父页面传入的数据

  const [pickerIsShow, setPickerIsShow] = useState(props.isShow);
  useEffect(() => {
    setPickerIsShow(isShow);
  }, [isShow]);

  useImperativeHandle(ref, () => ({
    close,
  }))

  function close() {
    setTimeout(() => {
      setPickerIsShow(false);
      // 延迟关闭, 因为MyTransition需要这段时间差执行动画效果, 否则看起来像没有动画效果似的突然消失了
      setTimeout(() => {
        setIsShow(false);
      }, 500);
    }, 0);
  } // 点击取消按钮

  return ReactDOM.createPortal(
    <div className="picker-container">
      <MyTransition name="myPopup" transitionShow={pickerIsShow}>
        {isShow && <section className="pop-cover" onClick={close}></section>}
      </MyTransition>
      <MyTransition name="myOpacity" transitionShow={pickerIsShow}>
        {isShow && children}
      </MyTransition>
    </div>,
    document.body
  );
});

export default MyPickerModal;

ReactDOM.createPortal(element, 要插入这个elment的父元素, 一般写body, 也自己去html文件加一个元素, 插入到那个元素中去

10-17 06:05