React过渡动画
安装react-transition-group
# npm
npm install react-transition-group --save
# yarn
yarn add react-transition-group
可导入使用的有四个组件对象:
- Transition(不常用)
- CSSTransition(它的属性结合css控制组件出现、消失)
- SwitchTransition(控制两个组件之间状态切换)
- TransitionGroup(当有一组组件的动画时,需要使用它包裹)
使用CSSTransition
1】首先写css类名样式
-
CSSTransition执行过程中,有三个状态:appear、enter、exit;
-
它们有三种状态,需要定义对应的CSS样式:
-
- 第一类,开始状态:对于的类是-appear、-enter、-exit;
- 第二类:执行动画:对应的类是-appear-active、-enter-active、-exit-active;
- 第三类:执行结束:对应的类是-appear-done、-enter-done、-exit-done;
.card-enter, .card-appear {
opacity: 0;
transform: scale(.8);
}
.card-enter-active, .card-appear-active {
opacity: 1;
transform: scale(1);
transition: opacity 300ms, transform 300ms;
}
.card-exit {
opacity: 1;
}
.card-exit-active {
opacity: 0;
transform: scale(.8);
transition: opacity 300ms, transform 300ms;
}
2】CSSTransition组件属性
-
in:触发进入或者退出状态
-
- 如果添加了
unmountOnExit={true}
,那么该组件会在执行退出动画结束后被移除掉; - 当in为true时,触发进入状态,会添加-enter、-enter-acitve的class开始执行动画,当动画执行结束后,会移除两个class,并且添加-enter-done的class;
- 当in为false时,触发退出状态,会添加-exit、-exit-active的class开始执行动画,当动画执行结束后,会移除两个class,并且添加-enter-done的class;
- 如果添加了
-
classNames:动画class的名称
-
- 决定了在编写css时,对应的class名称:比如card-enter、card-enter-active、card-enter-done;
-
timeout:
-
- 过渡动画的时间
-
appear:
-
- 是否在初次进入添加动画(需要和in同时为true)
-
其他属性可以参考官网来学习:
-
- https://reactcommunity.org/react-transition-group/transition
CSSTransition对应的钩子函数:主要为了检测动画的执行过程,来完成一些JavaScript的操作
- onEnter:在进入动画之前被触发;
- onEntering:在应用进入动画时被触发;
- onEntered:在应用进入动画结束后被触发;
import React, { Component } from 'react'
import { CSSTransition } from 'react-transition-group';
import '../style/ReactTransition.css'
interface IProps { }
interface IState {
isShowCard: boolean
}
class ReactTransition extends Component<IProps, IState> {
constructor(props) {
super(props)
this.state = {
isShowCard: true
}
}
render() {
return (
<div>
<button onClick={e => this.setState({ isShowCard: !this.state.isShowCard })}>显示/隐藏</button>
<CSSTransition
in={this.state.isShowCard}//为true进入显示组件(主要通过in属性来控制组件状态)
classNames="card"//设置类名的前缀
timeout={1000}//设置过渡动画事件
unmountOnExit={true}//消失动画结束后 + display:none
>
<div>哈哈哈</div>
</CSSTransition>
</div>
)
}
}
export default ReactTransition
使用SwitchTransition
SwitchTransition可以完成两个组件之间切换的炫酷动画:
- 比如我们有一个按钮需要在on和off之间切换,我们希望看到on先从左侧退出,off再从右侧进入;
- 这个动画在vue中被称之为 vue transition modes;
- react-transition-group中使用SwitchTransition来实现该动画;
SwitchTransition中主要有一个属性:mode,有两个值
- in-out:表示新组件先进入,旧组件再移除;
- out-in:表示就组件先移除,新组建再进入;
SwitchTransition还是需要通过CSSTransition来进行控制,使用key属性来控制(不能使用in属性)
- SwitchTransition组件里面要有CSSTransition或者Transition组件,不能直接包裹你想要切换的组件;
- SwitchTransition里面的CSSTransition或Transition组件不再像以前那样接受in属性来判断元素是何种状态,取而代之的是key属性;
import React, { Component } from 'react'
import { CSSTransition, SwitchTransition } from 'react-transition-group';
import '../style/ReactTransitionSwitch.css'
interface IProps {
}
interface IState {
isOn: boolean
}
class ReactTransitionSwitch extends Component<IProps, IState> {
constructor(props: IProps) {
super(props)
this.state = {
isOn: true
}
}
render() {
const { isOn } = this.state;
return (
<div>
<SwitchTransition mode="out-in">
<CSSTransition classNames="btn"
timeout={500}
key={isOn ? "on" : "off"}>
{
<button onClick={() => {
this.setState({ isOn: !isOn })
}}>
{isOn ? "on" : "off"}
</button>
}
</CSSTransition>
</SwitchTransition>
</div>
)
}
}
export default ReactTransitionSwitch
ReactTransitionSwitch.css
.btn-enter {
transform: translate(100%, 0);
opacity: 0;
}
.btn-enter-active {
transform: translate(0, 0);
opacity: 1;
transition: all 500ms;
}
.btn-exit {
transform: translate(0, 0);
opacity: 1;
}
.btn-exit-active {
transform: translate(-100%, 0);
opacity: 0;
transition: all 500ms;
}
使用TransitionGroup
当我们有一组动画时,需要将这些CSSTransition放入到一个TransitionGroup中来完成动画:
import React, { PureComponent } from 'react'
import { CSSTransition, TransitionGroup } from 'react-transition-group';
import '../style/ReactTransitionGroup.css';
interface Iprops {
}
interface Istate {
friends: Array<string>,
count: number
}
class ReactTransitionGroup extends PureComponent<Iprops, Istate> {
constructor(props: Iprops) {
super(props);
this.state = {
friends: [],
count: 0
}
}
render() {
return (
<div>
<TransitionGroup>
{
this.state.friends.map((item, index) => {
return (
<CSSTransition classNames="friend" timeout={300} key={index}>
<div>{item}
<button onClick={() => {
let friends = [...this.state.friends]
friends.splice(index, 1)
this.setState({ friends: friends })
}}>×</button>
</div>
</CSSTransition>
)
})
}
</TransitionGroup>
<button className='buttonAdd' onClick={() => {
this.setState({
friends: [...this.state.friends, (this.state.count + 1).toString()],
count: this.state.count + 1
})
}}>+friend</button>
</div>
)
}
}
export default ReactTransitionGroup
ReactTransitionGroup.css
.friend-enter {
opacity: 0;
}
.friend-enter-active {
opacity: 1;
transition: opacity 500ms ease-in;
}
.friend-exit {
opacity: 1;
}
.friend-exit-active {
opacity: 0;
transition: opacity 500ms ease-in;
}
.buttonAdd {
position: absolute;
top: 50%;
left: 55%;
}