目录
- 3,SwitchTransition
- 3.1,原理
- 3.1.2,key
- 3.1.2,mode
- 3.2,举例
- 3.3,结合 animate.css
- 4,TransitionGroup
- 4.1,其他属性
- 4.1.2,appear
- 4.1.2,component
- 4.1.3,classNames
接上面文章 React动画(上)
3,SwitchTransition
官方文档
在上篇文章中,用 CSSTransition 做了一个动画:
可以看到,这2个元素的动画是同时发生的,因为使用同一个状态变量控制的(代码参考上篇文章)
而 SwitchTransition 组件是专门用来做切换动画的,并且2个元素的动画是有先后顺序的。
元素1完成退出动画后,元素2再开始进入动画。
3.1,原理
默认情况下(mode="out-in"
),通过改变状态变量来改变 key 值,才能开始切换动画,
key
属性替换了之前的in
属性。
如果默认 state=true
,渲染元素1,则切换状态时的动画过程:
- 先给元素1添加类名
exit exit-active
,元素1执行退出动画。 - 等元素1的退出动画完成(过渡时间结束),再给元素2添加类名
enter enter-active
执行进入动画。 - 等元素2的进入动画完成,类名切换为
enter-done
。
所以,只需要设置这5个类名对应的样式即可。
如果进入动画结束后,用的默认样式(比如:
opacity: 1
)那类名enter-done
也不用设置。
3.1.2,key
因为会将退出动画和进入动画对应的类名,设置到对应的元素上,来实现切换动画。
所以如果不设置,那所有的类名会加到同一个元素上,结果是该元素无限进入循环动画(退出-进入-退出…)
key 只要保证唯一,能区分为2个元素即可。
3.1.2,mode
默认 out-in
,具体动画过程上面已经介绍了。
而 in-out
,如果默认 state=true
,渲染元素1,则切换状态时的动画过程:
- 保持元素1不变,为元素2添加
enter enter-active
执行进入动画。 - 过渡时间结束,元素2的类名变为
enter-done
,同时为元素1添加类名exit exit-active
,开始退出动画。 - 过渡时间结束,元素1被移除。
相当于先执行了一次元素2的进入动画,之后再开始执行元素1的退出动画。
3.2,举例
import { CSSTransition, SwitchTransition } from "react-transition-group";
import { useRef, useState } from "react";
import "./App.css";export default function App() {const [state, setState] = useState(true);return (<SwitchTransition><CSSTransition key={state} timeout={500}><button onClick={() => setState(!state)}>{state ? "状态1" : "状态2"}</button></CSSTransition></SwitchTransition>);
}
/* App.css */
.enter {opacity: 0;
}
.enter-active {opacity: 1;transition: opacity 1s;
}.exit {opacity: 1;
}
.exit-active {opacity: 0;transition: opacity 1s;
}
效果:
同样的,要在过渡完成后执行 transitionend
事件,可以:
export default function App() {const [state, setState] = useState(true);const refBtn1 = useRef(null);const refBtn2 = useRef(null);const nodeRef = state ? refBtn1 : refBtn2;return (<SwitchTransition><CSSTransitionkey={state}timeout={1000}nodeRef={nodeRef}addEndListener={() => {nodeRef.current.addEventListener("transitionend",() => {console.log("过渡结束");},{ once: true });}}><button ref={nodeRef} onClick={() => setState((state) => !state)}>{state ? "状态1" : "状态2"}</button></CSSTransition></SwitchTransition>);
}
3.3,结合 animate.css
animate 样式举例1,animate 样式举例2
安装:
npm install animate.css -S
样例完整代码:
import { CSSTransition, SwitchTransition } from "react-transition-group";
import { useState } from "react";
import "animate.css";export default function App() {const [state, setState] = useState(true);return (<SwitchTransition><CSSTransitionkey={state}timeout={1000}classNames={{appearActive: "animate__fadeInRight",enterActive: "animate__fadeInRight",exitActive: "animate__fadeOutLeft",}}><button className="animate__animated" onClick={() => setState(!state)}>{state ? "状态1" : "状态2"}</button></CSSTransition></SwitchTransition>);
}
效果:
4,TransitionGroup
官方文档
它接收一组 CSSTransition 或 Transition,统一控制它们的进入和退出动画。
和 SwitchTransition 一样,会添加对应的类名来实现动画。
经典例子:待办列表,可以动态新增或删除待办项,同时为每一项都应用动画。
import { TransitionGroup, CSSTransition } from "react-transition-group";
import { useState } from "react";
import { v4 as uuidv4 } from "uuid";
import "./App.css";export default function App() {const [todoList, setTodoList] = useState([{ id: uuidv4(), content: "学习" },{ id: uuidv4(), content: "吃饭" },{ id: uuidv4(), content: "睡觉" },]);return (<><TransitionGroup>{todoList.map((item) => (<CSSTransition key={item.id} timeout={500}><div><span>{item.content}</span><buttononClick={() => {const resultItem = todoList.filter((f) => f.id !== item.id);setTodoList(resultItem);}}>删除</button></div></CSSTransition>))}</TransitionGroup><buttononClick={() => {const answer = window.prompt();setTodoList([...todoList,{id: uuidv4(),content: answer,},]);}}>新增</button></>);
}
4.1,其他属性
4.1.2,appear
统一添加加载动画,同时会有 appear
,appear-active
,appear-done
类名。
4.1.2,component
控制渲染的容器的节点类名,默认 div
,null
表示不渲染节点。
<TransitionGroup appear component="ul">
4.1.3,classNames
是 component
对应节点的类名,不是动画类名前缀。
动画类名前缀,还是要添加到 CSSTransition 组件上。
以上。