一、是什么
在日常开发中,页面切换时的转场动画是比较基础的一个场景
当一个组件在显示与消失过程中存在过渡动画,可以很好的增加用户的体验
在react
中实现过渡动画效果会有很多种选择,如react-transition-group
,react-motion
,Animated
,以及原生的CSS
都能完成切换动画
二、如何实现
在react
中,react-transition-group
是一种很好的解决方案,其为元素添加enter
,enter-active
,exit
,exit-active
这一系列勾子
可以帮助我们方便的实现组件的入场和离场动画
其主要提供了三个主要的组件:
- CSSTransition:在前端开发中,结合 CSS 来完成过渡动画效果
- SwitchTransition:两个组件显示和隐藏切换时,使用该组件
- TransitionGroup:将多个动画组件包裹在其中,一般用于列表中元素的动画
CSSTransition
其实现动画的原理在于,当CSSTransition
的in
属性置为true
时,CSSTransition
首先会给其子组件加上xxx-enter
、xxx-enter-active
的class
执行动画
当动画执行结束后,会移除两个class
,并且添加-enter-done
的class
所以可以利用这一点,通过css
的transition
属性,让元素在两个状态之间平滑过渡,从而得到相应的动画效果
当in
属性置为false
时,CSSTransition
会给子组件加上xxx-exit
和xxx-exit-active
的class
,然后开始执行动画,当动画结束后,移除两个class
,然后添加-enter-done
的class
如下例子:
export default class App2 extends React.PureComponent {state = {show: true};onToggle = () => this.setState({show: !this.state.show});render() {const {show} = this.state;return (<div className={'container'}><div className={'square-wrapper'}><CSSTransitionin={show}timeout={500}classNames={'fade'}unmountOnExit={true}><div className={'square'} /></CSSTransition></div><Button onClick={this.onToggle}>toggle</Button></div>);}
}
对应css
样式如下:
.fade-enter {opacity: 0;transform: translateX(100%);
}.fade-enter-active {opacity: 1;transform: translateX(0);transition: all 500ms;
}.fade-exit {opacity: 1;transform: translateX(0);
}.fade-exit-active {opacity: 0;transform: translateX(-100%);transition: all 500ms;
}
SwitchTransition
SwitchTransition
可以完成两个组件之间切换的炫酷动画
比如有一个按钮需要在on
和off
之间切换,我们希望看到on
先从左侧退出,off
再从右侧进入
SwitchTransition
中主要有一个属性mode
,对应两个值:
- in-out:表示新组件先进入,旧组件再移除;
- out-in:表示就组件先移除,新组建再进入
SwitchTransition
组件里面要有CSSTransition
,不能直接包裹你想要切换的组件
里面的CSSTransition
组件不再像以前那样接受in
属性来判断元素是何种状态,取而代之的是key
属性
下面给出一个按钮入场和出场的示例,如下:
import { SwitchTransition, CSSTransition } from "react-transition-group";export default class SwitchAnimation extends PureComponent {constructor(props) {super(props);this.state = {isOn: true}}render() {const {isOn} = this.state;return (<SwitchTransition mode="out-in"><CSSTransition classNames="btn"timeout={500}key={isOn ? "on" : "off"}>{<button onClick={this.btnClick.bind(this)}>{isOn ? "on": "off"}</button>}</CSSTransition></SwitchTransition>)}btnClick() {this.setState({isOn: !this.state.isOn})}
}
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
中来完成动画
同样CSSTransition
里面没有in
属性,用到了key
属性
TransitionGroup
在感知children
发生变化的时候,先保存移除的节点,当动画结束后才真正移除
其处理方式如下:
-
插入的节点,先渲染dom,然后再做动画
-
删除的节点,先做动画,然后再删除dom
如下:
import React, { PureComponent } from 'react'
import { CSSTransition, TransitionGroup } from 'react-transition-group';export default class GroupAnimation extends PureComponent {constructor(props) {super(props);this.state = {friends: []}}render() {return (<div><TransitionGroup>{this.state.friends.map((item, index) => {return (<CSSTransition classNames="friend" timeout={300} key={index}><div>{item}</div></CSSTransition>)})}</TransitionGroup><button onClick={e => this.addFriend()}>+friend</button></div>)}addFriend() {this.setState({friends: [...this.state.friends, "coderwhy"]})}
}
对应css
如下:
.friend-enter {transform: translate(100%, 0);opacity: 0;
}.friend-enter-active {transform: translate(0, 0);opacity: 1;transition: all 500ms;
}.friend-exit {transform: translate(0, 0);opacity: 1;
}.friend-exit-active {transform: translate(-100%, 0);opacity: 0;transition: all 500ms;
}