likes
comments
collection
share

React 过渡&动画

作者站长头像
站长
· 阅读数 20

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、enterexit

  • 它们有三种状态,需要定义对应的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;
    }
    

    React 过渡&动画

4. TransitionGroup

  • 官网

  • TransitionGroup组件能实现动画组

    • component:修改组件渲染成的元素类型,默认是div
    • CSSTransition 组件绑定key 不要使用index,删除时index变化会导致动画加载不正确
  • 代码演示

    • 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;
    }
    

    React 过渡&动画

转载自:https://juejin.cn/post/7144961780493025316
评论
请登录