React动画库:react-transition-group(官网)
React动画 - Transition
Transition有4个状态
'entering'
'entered'
'exiting'
'exited'
可以通过in
来切换状态,timeout
决定状态的持续时间
当in
为true时,为进入状态,,发生:
- 为Transition内部的DOM根元素(后续统一称之为DOM元素)添加样式entering类名
- 当timeout结束后,去掉之前的样式,Dom元素添加entered类名
当in
为false时,为退出状态,,发生:
- 为Transition内部的DOM根元素添加样式exiting类名
- 当timeout结束后,去掉之前的样式,Dom元素添加exited类名
import { Transition } from 'react-transition-group';
import { useRef } 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 },
};
function Fade({ in: inProp }) {
const nodeRef = useRef(null);
return (
<Transition nodeRef={nodeRef} in={inProp} timeout={duration}>
{state => (
<div ref={nodeRef} style={{
...defaultStyle,
...transitionStyles[state]
}}>
I'm a fade Transition!
</div>
)}
</Transition>
);
}
React动画 - CSSTransition
当进入时,发生:
- 为CSSTransition内部的DOM根元素(后续统一称之为DOM元素)添加样式enter
- 在一下帧(enter样式已经完全应用到了元素),立即为该元素添加样式enter-active
- 当timeout结束后,去掉之前的样式,添加样式enter-done
当退出时,发生:
- 为CSSTransition内部的DOM根元素(后续统一称之为DOM元素)添加样式exit
- 在一下帧(exit样式已经完全应用到了元素),立即为该元素添加样式exit-active
- 当timeout结束后,去掉之前的样式,添加样式exit-done
设置classNames属性,可以指定类样式的名称
- 字符串:为类样式添加前缀
- 对象:为每个类样式指定具体的名称(非前缀)
关于首次渲染时的类样式,appear、apear-active、apear-done,它和enter的唯一区别在于完成时,会同时加入apear-done和enter-done
还可以与Animate.css联用
function App() {
const [inProp, setInProp] = useState(false);
const nodeRef = useRef(null);
return (
<div>
<CSSTransition nodeRef={nodeRef} in={inProp} timeout={200} classNames="my-node">
<div ref={nodeRef}>
{"I'll receive my-node-* classes"}
</div>
</CSSTransition>
<button type="button" onClick={() => setInProp(true)}>
Click to Enter
</button>
</div>
);
}
React动画 - SwitchTransition
用于有秩序的切换内部组件
默认情况下:out-in
- 当key值改变时,会将之前的DOM根元素添加退出样式(exit,exit-active)
- 退出完成后,将该DOM元素移除
- 重新渲染内部DOM元素
- 为新渲染的DOM根元素添加进入样式(enter, enter-active, enter-done)
in-out:
- 重新渲染内部DOM元素,保留之前的元素
- 为新渲染的DOM根元素添加进入样式(enter, enter-active, enter-done)
- 将之前的DOM根元素添加退出样式(exit,exit-active)
- 退出完成后,将该DOM元素移除
function App() {
const [state, setState] = useState(false);
const helloRef = useRef(null);
const goodbyeRef = useRef(null);
const nodeRef = state ? goodbyeRef : helloRef;
return (
<SwitchTransition>
<CSSTransition
key={state ? "Goodbye, world!" : "Hello, world!"}
nodeRef={nodeRef}
addEndListener={(node, done) => node.addEventListener("transitionend", done, false)}
classNames='fade'
>
<button ref={nodeRef} onClick={() => setState(state => !state)}>
{state ? "Goodbye, world!" : "Hello, world!"}
</button>
</CSSTransition>
</SwitchTransition>
);
}
.fade-enter{
opacity: 0;
}
.fade-exit{
opacity: 1;
}
.fade-enter-active{
opacity: 1;
}
.fade-exit-active{
opacity: 0;
}
.fade-enter-active,
.fade-exit-active{
transition: opacity 500ms;
}
React动画 - TransitionGroup
该组件的children,接收多个Transition或CSSTransition组件,该组件用于根据这些子组件的key值,控制他们的进入和退出状态
import React, { useState } from 'react'
import uuid from "uuid";
import { TransitionGroup, CSSTransition } from "react-transition-group"
import "./App.css"
export default function App() {
const [tasksList, setTasksList] = useState([
{ id: uuid(), name: "任务1" },
{ id: uuid(), name: "任务2" },
]);
return (
<div>
<TransitionGroup appear component="ul" className="abc">
{
tasksList.map(t => (
<CSSTransition timeout={2000} key={t.id}>
<li>{t.name} <button
onClick={() => {
var newTasks = tasksList.filter(it => it.id !== t.id);
setTasksList(newTasks);
}}
>删除</button></li>
</CSSTransition>
))
}
</TransitionGroup>
<button onClick={() => {
var name = window.prompt("请输入任务名称");
setTasksList([...tasksList, { id: uuid(), name }])
}}>添加一个任务</button>
</div>
)
}
.exit{
transform-origin: left top;
}
.exit-active{
transform: scale(0);
transition: 2s;
}
.enter{
transform-origin: left top;
transform: scale(0);
}
.enter-active{
transform: scale(1);
transition: 2s;
}