React--过渡动画

572 阅读3分钟

过渡动画

  • React 社区提供了 react-transition-group 用来完成过渡动画,该库可以实现组件的入场和离场
  • 官网: reactcommunity.org/react-trans…
  • 安装 react-transition-group 第三方库
 npm i react-transition-group --save

react-transition-group 主要包含四个组件:

  • Transition: 该组件是和平台无关的组件
  • CSSTransition: 通常使用该组件来完成过渡动画效果
  • SwitchTransition: 可控制两个组件显示和隐藏的切换
  • TransitionGroup: 将多个动画组件包裹在其中,一般用于列表中元素的动画

CSSTransition

  • CSSTransition 是基于 Transition 组件构建的
  • CSSTransition 执行过程中有三个状态:appearenterexit

对应的三种状态都需要定义对应的 CSS 样式

  • 开始状态: 对于的类是 -appear-enter(进入)exit(离开)
  • 执行动画: 对应的类是 -appear-active-enter-active-exit-active
  • 执行结束: 对应的类是 -appear-done-enter-done-exit-done
 import { CSSTransition } from 'react-transition-group';
 import './style.css';
 ​
 <div>
   <button onClick={e => this.setState({ isShowTitle: !isShowTitle })}>显示/隐藏</button>
     <CSSTransition 
       in={isShowTitle} // 判断显示的条件
       classNames='title' // 过渡类名
       timeout={2000} // 过渡时间(必须)
       unmountOnExit // 退出时销毁
     > 
       <h2>App</h2>
     </CSSTransition>
 </div>
 /* 定义进入时的过渡动画 */
 .title-enter {
   opacity: 0;
 }
 ​
 .title-enter-active {
   opacity: 1;
   transition: opacity 2s ease;
 }

常见属性

  • in: 触发进入或者退出状态

    • true 时触发进入状态,会添加 -enter-enter-acitveclass 开始执行动画,结束后将其移除,并添加 -enter-doneclass
    • false 时触发退出状态,会添加 -exit-exit-activeclass 开始执行动画,结束后会移出 并添加 -enter-doneclass
  • unmountOnExit:组件会在执行退出动画结束后被销毁掉

  • classNames: 对应的 class 名称

  • timeout: 过渡动画的时间

  • appear: 是否在初次进入添加动画(需要和 in 同时为 true)

 <CSSTransition 
   in={isShowTitle} 
   classNames='title' 
   timeout={2000}
   unmountOnExit
   appear
 > 
 .title-enter, .title-appear {
   opacity: 0;
 }
 ​
 .title-enter-active, .title-appear-active {
   opacity: 1;
   transition: opacity 2s ease;
 }

钩子函数

  • CSSTransition 对应的钩子函数,主要为了检测动画的执行过程,来完成一些 JavaScript 的操作

主要的钩子函数如下:

  • onEnter 在进入动画之前被触发
  • onEntering 在应用进入动画时被触发
  • onEntered 在应用进入动画结束后被触发
  • onExit 在进入动画之前被触发
  • onExiting 在应用进入动画时被触发
  • onExited 在应用进入动画结束后被触发
 <CSSTransition 
   in={isShowTitle} 
   classNames='title' 
   timeout={2000}
   unmountOnExit
   onEnter={e => console.log('开始执行动画')}
   onEntering={e => console.log('执行进入动画')}
   onEntered={e => console.log('进入动画结束')}
   onExit={e => console.log('开始离开动画')}
   onExiting={e => console.log('执行离开动画')}
   onExited={e => console.log('离开动画结束')}
 > 

SwitchTransition

  • SwitchTransition 可以完成两个组件之间切换的动画
  • 使用 react-transition-group 中提供的 SwitchTransition 来实现该类型的动画
 import { SwitchTransition, CSSTransition } from 'react-transition-group';
 ​
 <div>
   <SwitchTransition mode='out-in'> {/* mode为切换的模式 */}
     <CSSTransition 
       key={isLogin ? 'exit' : 'login'} {/* 用于执行切换动画 */}
       classNames="login"
       timeout={1000}
     >
       <button onClick={e => this.setState({ isLogin: !isLogin })}>{isLogin?'退出':'登录'}</button>
     </CSSTransition>
   </SwitchTransition>
 </div>
 .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: translate(-100px);
   opacity: 0;
   transition: all 1s ease;
 }
  • 通过 CSSTransition 不同的 key 属性切换,让切换动画执行

mode 属性有两个值

  • in-out: 表示新组件先进入,旧组件再移除
  • out-in: 表示就组件先移除,新组件再进入

TransitionGroup

  • 当有一组动画时,需要将这些 CSSTransition 放入到一个 TransitionGroup 中来完成动画
 const books = [
   { name: '你不知道的JS', price: 99, id: 1},
   { name: 'JS高级程序设计', price: 88, id: 2},
   { name: 'VueJS高级设计', price: 77, id: 3}
 ];
 ​
 <div>
   <h2>书籍列表</h2>
   <TransitionGroup component='ul'> {/* component: 指定需要渲染的标签 */}
     {
       books.map((item) => (
         <CSSTransition key={item.id} classNames='book' timeout={1000}>
           <li key={item.id}>{item.name}-{item.price}</li>
         </CSSTransition>
       ))
     }
   </TransitionGroup>
   <button onClick={e => this.addNewBook()}>添加新书籍</button>
 </div>
  • 此处的 key 最好保证是唯一的,否则动画可能出现差错
 .book-enter {
   transform: translateX(100px);
   opacity: 0;
 }
 ​
 .book-enter-active {
   transform: translateX(0);
   opacity: 1;
   transition: all 1s ease;
 }