React 过渡&动画
React 中的动画与 Vue 中的类似,更多内容可参考vue3-过渡&动画
1. react-transition-group
- React社区为我们提供了
react-transition-group
用来完成过渡动画- 这个库可以帮助我们方便的实现组件的 入场 和 离场 动画,使用时需要进行额外的安装:
# npm npm install react-transition-group --save # yarn yarn add react-transition-group
- 主要组件
-
Transition
- 该组件是一个和平台无关的组件(不一定要结合CSS)
- 在前端开发中,我们一般是结合CSS来完成样式,所以比较常用的是CSSTransition
-
CSSTransition
- 在前端开发中,通常使用CSSTransition来完成过渡动画效果
- SwitchTransition
- 两个组件显示和隐藏切换时,使用该组件
-
TransitionGroup
- 将多个动画组件包裹在其中,一般用于列表中元素的动画
-
2. CSSTransition
-
CSSTransition是基于Transition组件构建的:
-
CSSTransition执行过程中,有三个状态:appear、enter、exit
-
它们有三种状态,需要定义对应的CSS样式:
-
开始状态:对于的类是-appear、-enter、exit;
-
执行动画:对应的类是-appear-active、-enter-active、-exit-active;
-
执行结束:对应的类是-appear-done、-enter-done、-exit-done;
-
-
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:过渡动画的时间(尽量与css类中的动画时间保持一致),决定类名的添加和删除
-
appear:是否在初次进入添加动画(需要和in同时为true)
-
unmountOnExit:退出后卸载组件
-
-
CSSTransition对应的钩子函数:主要为了检测动画的执行过程,来完成一些JavaScript的操作
- onEnter:在进入动画之前被触发
- onEntering:在应用进入动画时被触发
- onEntered:在应用进入动画结束后被触发
-
代码演示
- App.jsx
import React, { createRef, PureComponent } from "react"; import { CSSTransition } from "react-transition-group"; import "./style.css"; export default class App extends PureComponent { constructor() { super(); this.state = { isShow: true, }; // 解决严格模式下 第三方库的报错 this.sectionRef = createRef() } render() { const { isShow } = this.state; return ( <div> <button onClick={(e) => this.setState({ isShow: !isShow })}> 切换 </button> {/* { isShow && <h2>哈哈哈</h2> } */} <CSSTransition nodeRef={this.sectionRef} appear in={isShow} unmountOnExit={true} classNames="fade" timeout={1500} onEnter={e => console.log("开始进入动画")} onEntering={e => console.log("执行进入动画")} onEntered={e => console.log("执行进入结束")} onExit={e => console.log("开始离开动画")} onExiting={e => console.log("执行离开动画")} onExited={e => console.log("执行离开结束")} > <div className="section" ref={this.sectionRef}> <h2>哈哈哈</h2> <p>我是内容</p> </div> </CSSTransition> </div> ); } }
- style.css
/* 进入动画 */ /* .fade-appear { transform: translateX(-150px); } .fade-appear-active { transform: translateX(0); transition: transform 1.5s ease-in; } */ .fade-appear, .fade-enter { opacity: 0; } .fade-appear-active, .fade-enter-active { opacity: 1; transition: opacity 1.5s ease; } /* 离开动画 */ .fade-exit { opacity: 1; } .fade-exit-active { opacity: 0; transition: opacity 2s ease; }
3. SwitchTransition
-
SwitchTransition可以完成两个组件之间切换的炫酷动画:
- 比如我们有一个按钮需要在on和off之间切换,我们希望看到on先从左侧退出,off再从右侧进入
- 这个动画在vue中被称之为 vue transition modes
- react-transition-group中使用SwitchTransition来实现该动画
-
SwitchTransition中主要有一个属性:mode,有两个值
- in-out:表示新组件先进入,旧组件再移除;
- out-in:表示旧组件先移除,新组件再进入;
-
SwitchTransition的使用
- SwitchTransition组件里面要有CSSTransition或者Transition组件,不能直接包裹你想要切换的组件
- SwitchTransition里面的CSSTransition或Transition组件不再像以前那样接受in属性来判断元素是何种状态,取而代之的是key属性
-
代码演示
- App.jsx
import React, { PureComponent } from 'react' import { SwitchTransition, CSSTransition } from 'react-transition-group' import './style.css' export default class App extends PureComponent { constructor() { super() this.state = { isLogin: true } } render() { const { isLogin } = this.state return ( <div> <h2>App</h2> <SwitchTransition mode='out-in'> <CSSTransition key={isLogin ? 'exit' : 'login'} classNames='login' timeout={1000} > <button onClick={e => this.setState({isLogin: !isLogin})}> { isLogin ? '退出' : '登录' } </button> </CSSTransition> </SwitchTransition> </div> ) } }
- style.css
.login-enter { transform: translateX(100px); opacity: 0; } .login-enter-active { transform: translateX(0); opacity: 1; transition: all 1s ease; } .login-exit { transform: translateX(0); opacity: 1; } .login-exit-active { transform: translateX(-100px); opacity: 0; transition: all 1s ease; }
4. TransitionGroup
-
TransitionGroup
组件能实现动画组- component:修改组件渲染成的元素类型,默认是
div
CSSTransition
组件绑定key 不要使用index,删除时index变化会导致动画加载不正确
- component:修改组件渲染成的元素类型,默认是
-
代码演示
- App.jsx
import React, { PureComponent } from 'react' import { TransitionGroup, CSSTransition } from 'react-transition-group' import './style.css' export default class App extends PureComponent { constructor() { super() this.state = { books: [ { id: 1, name: '你不知道的JavaScript', price: 98 }, { id: 2, name: 'JavaScript高级程序设计', price: 128 }, { id: 3, name: 'Vue3指南', price: 88 }, { id: 4, name: 'React实战教程', price: 88 } ] } } addNewBook() { const books = [...this.state.books] books.push({ id: new Date().getTime(), name: 'CSS动画教程', price: 68 }) this.setState({books}) } removeBook(index) { const books = [...this.state.books] books.splice(index, 1) this.setState({books}) } render() { const { books } = this.state return ( <div> <h2>书籍列表</h2> <TransitionGroup component='ul'> { books.map((book, index) => { return ( <CSSTransition key={book.id} classNames='book' timeout={1000}> <li> <span>{book.name}-{book.price}</span> <button onClick={e => this.removeBook(index)}>删除</button> </li> </CSSTransition> ) }) } </TransitionGroup> <button onClick={e => this.addNewBook()}>添加新书籍</button> </div> ) } }
- style.css
.book-enter { transform: translateX(150px); opacity: 0; } .book-enter-active { transform: translateX(0); opacity: 1; transition: all 1s ease; } .book-exit { transform: translateX(0); opacity: 1; } .book-exit-active { transform: translateX(150px); opacity: 0; transition: all 1s ease; }
转载自:https://juejin.cn/post/7144961780493025316