目录
- 1,Transition
- 一些常用 props
- 1,mountOnEnter
- 2,unmountOnExit
- 3,appear
- 2,CSSTransition
- 2.1,和 Transition 组件的区别
- 2.2,举例
- 2.3,常用 props
- 2.3.1,classNames
- 2.3.2,appear
- 2.4,结合 animate.css
使用 react-transition-group 来实现动画。总共有4个动画组件,覆盖大多应用场景。
1,Transition
官方文档
过渡动画的原理,和 Vue的过渡动画 类似。分为2个阶段:
- 进入(enter)过渡动画,对应的状态有3个,
- 进入前的初始状态
default
; - 动画进行中的状态
entering
- 进入后的结束状态
entered
- 进入前的初始状态
- 退出(exit / leave)过渡动画,对应的状态也是3个,
- 退出前的初始状态
entered
exiting
exited
- 退出前的初始状态
注意,
进入前的初始状态和exited
是一个状态。
退出前的初始状态和entered
也是一个状态。
以一个渐入渐出动画举例,
.default {transition: opacity 2s ease-in-out;
}
.default, .exiting, .exited{opacity: 0;
}
.entering, .entered {opacity: 1;
}
官方文档的例子:
import { Transition } from "react-transition-group";
import { useRef, useState } 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 },
};/*** Transition.children 是一个函数,函数的返回值是要进行动画的元素。* 函数会随着过渡动画的进行而调用(进入动画会调用3次,对应3种状态),参数 state 就是当前过渡状态。* @param {in} boolean,动画开关。从 false-> true,开启进入动画,反之退出动画。* @returns*/
function Fade({ in: inProp }) {const nodeRef = useRef(null);return (<TransitionnodeRef={nodeRef}in={inProp}timeout={duration}addEndListener={() => {nodeRef.current.addEventListener("transitionend",() => {console.log("过渡结束");},{ once: true });}}>{(state) => (<divref={nodeRef}style={{...defaultStyle,...transitionStyles[state],}}>I'm a fade Transition!</div>)}</Transition>);
}export default function App() {const [visible, setVisible] = useState(true);return (<><buttononClick={() => {setVisible(!visible);}}>切换动画</button><Fade in={visible} /></>);
}
效果:
也可以不用内联样式,而用 class
来添加更多的样式:
<div className={state}>I'm a fade Transition!</div>
一些常用 props
1,mountOnEnter
延迟挂载。顾名思义,在进入动画开始前再加载要进行动画的元素。默认 false
立即加载。
比如,对渐入渐出动画来说,如果初始值 in={false}
,也就是说元素一开始是隐藏的。
- 默认情况下
mountOnEnter={false}
元素依然会被挂载到 DOM 中,等待动画开始。 - 如果设置
mountOnEnter
或mountOnEnter={true}
则元素延迟挂载,一开始并不会挂载到DOM中,直到动画开始才挂载并进行动画。
2,unmountOnExit
顾名思义,在退出动画结果后,是否在DOM中直接卸载动画元素。默认 false
不卸载。
3,appear
默认情况下,在元素挂载阶段,如果 in={true}
则直接进入动画的最终状态,整个过程 Transition.children
只会调用一次,参数 state=entered
。
此时设置 appear
或 appear={true}
,则进入动画会经历完整3个阶段,函数也会运行 3 次。
注意,
Transition
组件中并没有提供appear
这个状态,所以也无法设置改状态下的样式。所以只是函数会运行3次而已。
如果想一开始就执行一次进入的过渡动画,得使用下面这个组件CSSTransition
。
还有其他的一些属性不多介绍了,比如设置过渡动画结束后的回调函数等。用到时参考官方文档即可。
2,CSSTransition
官方文档
2.1,和 Transition 组件的区别
- CSSTransition 是在 Transition 的基础上实现的,可以理解为是它的增强版,同时继承了它的所有属性 props。
- Transition 只是提供了基础的进入和退出动画,并将过渡状态
state
暴露出来,通过它来设置样式。更复杂的动画需要用到onEnter
等回调函数来实现。
CSSTransition 是基于 CSS 的过渡动画组件,只需要为不同的过渡状态指定相应的类名(classNames),CSSTransition 会自动在适当的时机添加或删除这些类。 - CSSTransition* 能够实现加载动画。
2.2,举例
import { CSSTransition } from "react-transition-group";
import { useState } from "react";
import "./App.css";export default function App() {const [inProp, setInProp] = useState(true);return (<div><CSSTransition in={inProp} timeout={200} classNames="crane"><div>classNames 是自定义类名前缀</div></CSSTransition><button type="button" onClick={() => setInProp(!inProp)}>进入/退出</button></div>);
}
.crane-enter {opacity: 0;
}
.crane-enter-active {opacity: 1;transition: opacity 200ms;
}
.crane-enter-done {opacity: 1;
}
.crane-exit {opacity: 1;
}
.crane-exit-active {opacity: 0;transition: opacity 200ms;
}.crane-exit-done {opacity: 0;
}
逻辑,动画效果和 Transition 组件差不多。同样的,进入和退出动画分别有3种状态,不过直接对应到类名上了:
- 进入动画
enter
,动画开始前的初始化类名。enter-active
,动画进行中的类名。enter-done
,动画结束后的类名。
- 退出动画
exit
exit-active
exit-done
- 还多了加载动画
appear
appear-active
appear-done
2.3,常用 props
2.3.1,classNames
有2种情况:
- 字符串,表示动画类名前缀(上面的例子已经演示了)。
- 对象,设置状态对应的动画类名(所以可结合 animate.css 使用,下文有举例)。
classNames={{appear: 'my-appear',appearActive: 'my-active-appear',appearDone: 'my-done-appear',enter: 'my-enter',enterActive: 'my-active-enter',enterDone: 'my-done-enter',exit: 'my-exit',exitActive: 'my-active-exit',exitDone: 'my-done-exit',
}}
2.3.2,appear
在 Transition 组件的 appear
属性中,介绍了它没有对应的状态来设置样式。而 CSSTransition 组件是有的。
举例:(只包含关键代码)
<CSSTransition in={true} appear classNames="crane"></CSSTransition>
.crane-appear {transform: translateX(200px);
}
.crane-appear-active {transform: translateX(0);transition: transform 200ms;
}
.crane-appear-done {transform: translateX(0);
}
这样,在页面加载完成时(刷新页面后),就会执行上面的动画了。
2.4,结合 animate.css
animate 样式举例1,animate 样式举例2
安装:
npm install animate.css -S
样例完整代码:
import { CSSTransition } from "react-transition-group";
import { useRef, useState } from "react";
import "./App.css";
import "animate.css";function MyCSSTransition({ in: inProp, children }) {return (<div><CSSTransitionin={inProp}appearmountOnEntertimeout={1000}classNames={{appearActive: "animate__fadeInRight",enterActive: "animate__fadeInRight",exitActive: "animate__fadeOutLeft",exitDone: "exit-done",}}><div className="animate__animated common">{children}</div></CSSTransition></div>);
}export default function App() {const [inProp, setInProp] = useState(true);return (<div className="app-box"><MyCSSTransition in={inProp}><h1>组件1</h1></MyCSSTransition><MyCSSTransition in={!inProp}><h1>组件2</h1></MyCSSTransition><button type="button" onClick={() => setInProp(!inProp)}>进入/退出</button></div>);
}
/* App.css */
.app-box {position: relative;margin-left: 80px;padding-top: 100px;width: 200px;
}
.common {position: absolute;top: 0;
}.exit-done {display: none;
}
效果:
注意点:
1,在引入 animate.css 后,对要进行动画的元素的添加基础类名animate__animated
,其他过渡动画添加 animate__动画类名
即可。比如:
<h1 class="animate__animated animate__bounce">An animated element</h1>
2,classNames 属性的类名最终会添加到 ref={nodeRef}
的元素上。
3,因为 animate.css 中的类名都是过渡动画的类名,所以只需要设置 appearActive
、enterActive
、exitActive
这3个进行中的状态类名+最终态类名即可。
4,注意也设置了 mountOnEnter 属性,这是为了让没有进行动画的元素先不加载,以免影响到进行加载动画 appearActive
的元素。
接下篇文章 React 动画(下)
以上。