React使用动画
我们在开发中可以使用一些动画来控制组件消失和隐藏的过渡动画,增加用户交互的体验。
React社区提供了一个库react-transition-group
来完成过渡动画。使用网址参考
安装方式:
//npm
npm install react-transition-group -S
//yarn
yarn add react-transition-group -D
这个库可以帮助我们实现组件的入场和离场动画,实际上就是为组件添加类名,根据不同的时刻,我们可以就此来设置过渡动画。
该库体积很小,主要包含四个组件:Transition
, CSSTransition
, SwitchTransition
,TransitionGroup
Transition
该组件是一个与平台无关的组件,不一定要结合css
,如果要结合css
可以使用CSSTransition
。
这个组件常用于组件的挂载和卸载的过渡动画,该组件默认情况下Transition
组件不会改变它呈现的组件的行为,它只跟踪组件的enter
和exit
状态。这取决于你赋予的状态效果。例如,当组件进入或退出时,我们可以向它添加style
样式,以下是一个案例:
import React, { PureComponent } from "react";
import { Transition } from "react-transition-group";
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 },
};
export default class transitionDemo extends PureComponent {
render() {
return (
<Transition in={this.props.in} timeout={duration}>
{(state) => (
<div
style={{
...defaultStyle,
...transitionStyles[state],
}}
>
I'm a fade Transition!
</div>
)}
</Transition>
);
}
}
import React, { useState } from "react";
import CSSTransitionDemo from "./CSSTransitionDemo";
import SwitchTransitionDemo from "./SwitchTransitionDemo";
import TransitionGroupDemo from "./TransitionGroupDemo";
import TransitionDemo from "./transitionDemo";
function App() {
const [show, setShow] = useState(false);
return (
<div className="App">
<TransitionDemo in={show} timeout={500} />
<button onClick={(e) => setShow(!show)}>点击隐藏</button>
</div>
);
}
export default App;
我们可以控制in
的值来控制为组件赋予状态
首先我们初始化in的值为false
,那么组件内容默认不会显示,即处于exited
状态,那么style
设置的样式透明为0,就不会显示。当我们点击按钮,组件进入entering
状态,当500ms(timeout)
后组件处于entered
状态。
再次点击按钮组件处于exiting
状态,延时之后组件就回归exited
状态了。
本质上就是在不同的状态添加不同的style
样式。
CSSTransition
该组件在组件切换的不同时刻为组件添加类名,我们可以按照这些类名来给组件添加动画。
该组件在执行的额过程中有三个状态,分别为:appear
,enter
,exit
每个状态对应一组类名:
appear
状态:-appear
,-enter
,-exit
enter
状态:-appear-active
,-enter-active
,-exit-active
exit
状态:-appear-done
,-enter-done
,-exit-done
组件常用的属性
in
触发进入或者退出状态。
当为true
的时候组件触发进入状态,会为组件添加class
类名 -enter
,-enter-acitve
,动画结束后移除之前的两个class
,并添加-enter-done
类名。
当为false
的时候组件触发离开状态,会为组件添加-exit
,-exit-active
这两个类名,当动画结束时移除这两个类名,添加类名-exit-done
className
动画class
类名的前缀。
决定了在编写css
时,对应的class
名称:比如card-enter
,card-enter-active
,card-enter-done
。class
类这个属性变化存在的时间是按照time
来设置的,反正最好保证和css
的动画时间一致
timeout
过渡动画的时间,决定了执行动画时对应类名的存在时间。
appear
该属性决定了是否在第一次进入时添加动画,需要一开始的in
为true
,即页面刷新和第一次加载进入时就会执行动画,也是添加对应的类。
unmountOnExit
退出动画结束后是否卸载组件,该值默认为false
还有常见的钩子函数等。
案例演示:
import React, { PureComponent } from "react";
import { CSSTransition } from "react-transition-group";
import "./csstransition.css";
export default class CSSTransitionDemo extends PureComponent {
constructor(props) {
super(props);
this.state = {
isShow: true,
};
}
render() {
return (
<div>
<CSSTransition
appear
unmountOnExit={false}
in={this.state.isShow}
classNames="card"
timeout={300}
onEnter={el=>{console.log('开始状态')}}
onEntering={el=>{console.log('进入状态')}}
>
<div>
<h2>哈哈啊</h2>
<h2>哈哈啊</h2>
<h2>哈哈啊</h2>
<h2>哈哈啊</h2>
</div>
</CSSTransition>
<button
onClick={(e) => {
this.setState({ isShow: !this.state.isShow });
}}
>
显示/隐藏
</button>
</div>
);
}
}
.card-enter, .card-appear {
opacity: 0;
}
.card-enter-active,.card-appear-active {
opacity: 1;
transition: opacity 300ms;
}
/* 显示动画结束*/
/* .card-enter-done. card-appear-done {
} */
.card-exit {
opacity: 1;
transform: scale(1);
}
.card-exit-active {
opacity: 0;
transform: scale(0.8);
transition: opacity 300ms,transform 300ms;
}
.card-exit-done {
opacity: 0;
transform: scale(0.6);
}
import CSSTransitionDemo from "./CSSTransitionDemo";
function App() {
const [show, setShow] = useState(false);
return (
<div className="App">
<CSSTransitionDemo />
</div>
);
}
export default App;
SwitchTransition
该组件可以完成两个组件切换时的动画显示。
常用属性mode
两个值:in-out
表示新组件先进来,旧组件再移除。out-in
表示旧组件先移除,新组件再进入。
注意:
SwitchTransition
组件里面要有CSSTransition
或者Transition
组件,不能直接包裹你想要切换的组件
SwitchTransition
里面的CSSTransition
或Transition
组件不再像以前那样接受in
属性来判断元素是何种状态,取而代之的是key
属性,保证不同状态的 key
不同即可。
案例展示:
import React, { PureComponent } from "react";
import "./switchtransition.css";
import { SwitchTransition, CSSTransition } from "react-transition-group";
export default class SwitchTransitionDemo extends PureComponent {
state = { isOn: true };
render() {
/* 关于为什么要设置time属性,动画执行的时间是按照css设置的,
而class类这个属性变化存在的时间是按照time来设置的,反正最好保证这两个时间一致 */
return (
<div style={{ textAlign: "center" }}>
<hr></hr>
<SwitchTransition mode="out-in">
<CSSTransition
key={this.state.isOn ? "on" : "off"}
classNames="btn"
timeout={300}
>
<button
onClick={(e) => {
this.setState({ isOn: !this.state.isOn });
}}
>
{this.state.isOn ? "on" : "off"}
</button>
</CSSTransition>
</SwitchTransition>
</div>
);
}
}
.btn-enter {
opacity: 0;
transform: translateX(100%);
}
.btn-enter-active {
opacity: 1;
transform: translateX(0);
transition: opacity 300ms, transform 300ms;
}
.btn-exit {
transform: translateX(0);
opacity: 1;
}
.btn-exit-active {
opacity: 0;
transform: translateX(-100%);
transition: opacity 300ms,transform 300ms;
}
import SwitchTransitionDemo from "./SwitchTransitionDemo";
function App() {
return (
<div className="App">
<SwitchTransitionDemo />
</div>
);
}
export default App;
TransitionGroup
当我们有一组动画要执行的时候可以使用该组件,比如一个列表增删时的过渡动画。
案例展示:
import React, { PureComponent } from "react";
import { TransitionGroup, CSSTransition } from "react-transition-group";
import "./transitiongroup.css";
export default class TransitionGroupDemo extends PureComponent {
state = {
arr: ["zhangsan", "lisi", "wan"],
};
render() {
return (
<div>
<button onClick={(e) => this.addArr()}>添加</button>
<ul>
<TransitionGroup>
{this.state.arr.map((item, index) => {
return (
<CSSTransition key={index} timeout={500} classNames="item">
<li>{item}</li>
</CSSTransition>
);
})}
</TransitionGroup>
</ul>
</div>
);
}
addArr() {
this.setState({
arr: [...this.state.arr, "haha"],
});
}
}
.item-enter {
opacity: 0;
}
.item-enter-active {
opacity: 1;
transition: opacity 500ms;
}
/* 显示动画结束*/
.item-enter-done {
}
.item-exit {
opacity: 1;
}
.item-exit-active {
opacity: 0;
transition: opacity 500ms;
}
.item-exit-done {
opacity: 0;
}
import TransitionGroupDemo from "./TransitionGroupDemo";
function App() {
return (
<div className="App">
<TransitionGroupDemo />
</div>
);
}
export default App;
目前到这里就结束了,这些动画只是基本使用,可以配合上一些动画第三库来食用更佳。