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文件加一个元素, 插入到那个元素中去