Appearance
深入动画
原生动画
在React中我们可以通过原生的CSS来实现过渡动画,但是React社区为我们提供了react-transition-group帮助我们快速过渡动画
使用原生的动画实现的动画过渡的效果
jsx
import React from "react";
import styled from 'styled-components'
const StyleDiv = styled.div`
width: ${props=>props.width};
height: ${props=>props.height};
background-color: skyblue;
opacity: ${props=>props.opacity};
transition: all 3s;
`
class App extends React.PureComponent{
constructor(props) {
super(props);
this.state = {
width:0,
height:0,
opacity:0
}
}
render() {
return(
<div>
<StyleDiv {...this.state}/>
<button onClick={()=>{this.btnClick()}}>按钮</button>
</div>
)
}
btnClick(){
this.setState({
width:'100px',
height:'100px',
opacity:1
})
}
}
export default App
动画容器组件
在React中提供了四个容器组件来实现动画效果
Transition容器组件
- 改组件是一个和平台无关的组件(不一定要结合CSS)
- 在前端开发中,我们一般是结合CSS来完成过渡动画,所以比较常用的是CSSTransition
CSSTransition容器组件
- 在前端开发中,通常使用CSSTransition来完成过渡动画效果
通过CSSTransition实现过渡效果
安装
shell script
npm i -S react-transition-group
使用
App.js
jsx
import React from "react";
import "./App.css"
import { CSSTransition } from "react-transition-group"
/**
* in :取值为一个布尔值,如果取值为false,触发退出动画,如果取值是true触发进入动画
* classNames: 指定动画类名的前缀
* timeout: 设置动画的超时时间
* unmountOnExit: 如果取值为true,表示动画结束后,删除对应的元素
* appear: 是否显示初始化的动画效果
*/
class App extends React.PureComponent{
constructor(props) {
super(props);
this.state = {
isShow:false
}
}
render() {
return(
<div>
<CSSTransition in={this.state.isShow} classNames={'box'} timeout={3000} unmountOnExit={true}>
<div>
</div>
</CSSTransition>
<button onClick={()=>{this.btnClick()}}>按钮</button>
</div>
)
}
btnClick(){
this.setState({
isShow:!this.state.isShow
})
}
}
export default App
App.css
css
.box-enter{
/**
进入动画执行之前绑定的类名
*/
width: 0;
height: 0;
opacity: 0;
background-color: skyblue;
}
.box-enter-active{
/**
进入动画执行过程中绑定的类名
*/
width: 100px;
height: 100px;
opacity: 1;
transition: all 3s;
}
.box-enter-done{
/**
进入动画执行完毕之后绑定的类名
*/
width: 100px;
height: 100px;
opacity: 1;
background-color: red;
}
.box-exit{
/**
退出动画执行之前绑定的类名
*/
width: 100px;
height: 100px;
opacity: 1;
background-color: red;
}
.box-exit-active{
/**
退出动画执行过程中绑定的类名
*/
width: 0;
height: 0;
opacity: 0;
transition: all 1s;
}
.box-exit-done{
/**
退出动画执行完毕之后绑定的类名
*/
width: 0;
height: 0;
opacity: 0;
background-color: skyblue;
}
如果在一开始设置当前的盒子是处于显示的状态,上面的代码无法触发初试化的动画效果,这时候需要加入一个属性以及CSS的初始化的动画效果
jsx
constructor(props) {
this.state = {
isShow:true
}
}
<CSSTransition in={this.state.isShow} classNames={'box'} timeout={1000}
unmountOnExit={true} appear>
App.css
css
.box-appear{
/**
初始化动画执行之前绑定的类名
*/
width: 0px;
height: 0px;
opacity: 0;
background-color: skyblue;
}
.box-appear-active{
/**
初始化动画执行过程中绑定的类名
*/
width: 100px;
height: 100px;
opacity: 1;
transition: all 1s
}
.box-appear-done{
/**
初始化动画执行完毕之后绑定的类名
*/
width: 100px;
height: 100px;
opacity: 1;
background-color: red;
}
在CSSTransition中还有回调函数具体参考官网(翻墙):
地址为:https://reactcommunity.org/react-transition-group/transition
SwitchTransition容器组件
实现组件的切换动画,借鉴于vue transition modes
两个组件显示与隐藏切换是,使用该组件
SwitchTransition可以完成组件切换的动画
SwitchTransition组件里面要有CSSTransition或者Transition组件,不能直接包裹你想要切换的组件
SwitchTransition里面的CSSTransition或者Transition组件不再像以前一样接收in属性来判断元素是何种状态,需要通过key属性
示例
jsx
import React from "react";
import "./App.css"
import { CSSTransition,SwitchTransition } from "react-transition-group"
class App extends React.PureComponent{
constructor(props) {
super(props);
this.state = {
isOn:true
}
}
render() {
return(
<div>
<SwitchTransition>
<CSSTransition key={this.state.isOn} timeout={3000} classNames={'btn'}>
<button onClick={()=>{this.setState({isOn:!this.state.isOn})}}>{this.state.isOn ?'on':'off'}</button>
</CSSTransition>
</SwitchTransition>
</div>
)
}
}
export default App
App.css
css
.btn-enter{
/**
进入动画执行之前绑定的类名
*/
opacity: 0;
transform: translateX(-100%);
}
.btn-enter-active{
/**
进入动画执行过程中绑定的类名
*/
opacity: 1;
transform: translate(0);
transition: all 3s;
}
.btn-enter-done{
/**
进入动画执行完毕之后绑定的类名
*/
}
.btn-exit{
/**
退出动画执行之前绑定的类名
*/
opacity: 1;
transform: translate(0);
}
.btn-exit-active{
/**
退出动画执行过程中绑定的类名
*/
opacity: 0;
transform: translate(100%);
transition: all 3s;
}
.btn-exit-done{
/**
退出动画执行完毕之后绑定的类名
*/
}
button{
padding: 10px 20px;
margin-left: 50%;
}
TransitionGroup容器组件
- 将多个动画组件包裹在其中,一般用于列表中元素的动画
当我们有一组组件需要执行动画时,就需要将这些CSSTransition放入到一个TransitionGroup中来完成动画
和SwitchTransition一样都需要使用key来触发
示例:
jsx
import React from "react";
import "./App.css"
import { CSSTransition,TransitionGroup } from "react-transition-group"
class App extends React.PureComponent{
constructor(props) {
super(props);
this.state = {
heroList:['虞姬','鲁班','火舞']
}
}
render() {
return(
<div>
{/*
注意点:无论是TransitionGroup还是SwitchTransition都必须是它直接的子元素才可以
*/}
<ul>
<TransitionGroup>
{
this.state.heroList.map((v,index)=>{
return (
<CSSTransition key={v} timeout={3000} classNames={'item'}>
<li key={v+index} onClick={()=>{this.removeHero(index)}}>{v}</li>
</CSSTransition>
)
})
}
</TransitionGroup>
</ul>
<button onClick={()=>{this.btnClick()}}>新增</button>
</div>
)
}
btnClick(){
this.setState({
heroList:[...this.state.heroList,...['你好']]
})
}
removeHero(index){
const list = this.state.heroList.filter((name,idx)=>{
return idx !==index
})
this.setState({
heroList:list
})
}
}
export default App
App.css
css
.item-enter{
/**
进入动画执行之前绑定的类名
*/
opacity: 0;
transform: translateX(100%);
}
.item-enter-active{
/**
进入动画执行过程中绑定的类名
*/
opacity: 1;
transform: translate(0);
transition: all 3s;
}
.item-enter-done{
/**
进入动画执行完毕之后绑定的类名
*/
}
.item-exit{
/**
退出动画执行之前绑定的类名
*/
opacity: 1;
transform: translate(0);
}
.item-exit-active{
/**
退出动画执行过程中绑定的类名
*/
opacity: 0;
transform: translate(100%);
transition: all 3s;
}
.item-exit-done{
/**
退出动画执行完毕之后绑定的类名
*/
}
button{
padding: 10px 20px;
margin-left: 50%;
}
注意点
在企业开发中,一定要保证CSSTransition中key的唯一性,不然重复的key,元素不会被创建