React(六)React过渡动画-CSS编写方式

React过渡动画

react-transition-group介绍

  • 在开发中,我们想要给一个组件的显示和消失添加某种过渡动画,提高用户体验→可通过react-transition-group实现。
  • React曾为开发者提供过动画插件 react-addons-css-transition-group,后由社区维护,形成了现在的 react-transitiongroup。
  • 该组件帮助我们实现组件的入场和离场动画。
  • 安装方式:
bash 复制代码
# npm
npm install react-transition-group --save
# yarn
yarn add react-transition-group

react-transition-group主要组件

该插件主要包含四个组件:

Transition:基础组件,用于管理单个组件的进入和退出动画

CSSTransition:基于 <Transition> 的高级组件,它通过添加 CSS 类名来实现动画效果

SwitchTransition:两个组件显示和隐藏切换时,使用该组件

TransitionGroup:将多个动画组件包裹在其中,一般用于列表中元素的动画;

CSSTransition

  1. 执行过程中的三个状态:appear、enter、exit
  2. 三种状态对应的CSS样式:
  • 开始状态:xxx-appear、xxx-enter、xxx-exit
  • 执行动画:xxx-appear-active、xxx-enter-active、xxx-exit-active;
  • 执行结束:xxx-appear-done、xxx-enter-done、xxx-exit-done;

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

  • 当in为true时,触发进入状态,会添加-enter、-enter-acitve的class开始执行动画,当动画执行结束后,会移除两个class, 并且添加-enter-done的class;
  • 当in为false时,触发退出状态,,会添加-exit、-exit-active的class开始执行动画,当动画执行结束后,会移除两个class,并且添加-enter-done的class;

App.jsx

javascript 复制代码
import React, { createRef, PureComponent } from 'react'
import { CSSTransition } from "react-transition-group"
import "./style.css"

export class App extends PureComponent {
  constructor(props) {
    super(props)

    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}
          in={isShow} 
          unmountOnExit={true} 
          classNames="why" 
          timeout={2000}
          appear
          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>
    )
  }
}

export default App

style.css

css 复制代码
/* 进入动画 */
/* .why-appear {
  transform: translateX(-150px);
}

.why-appear-active {
  transform: translateX(0);
  transition: transform 2s ease;
} */

.why-appear, .why-enter {
  opacity: 0;
}

.why-appear-active, .why-enter-active {
  opacity: 1;
  transition: opacity 2s ease;
}

/* 离开动画 */
.why-exit {
  opacity: 1;
}

.why-exit-active {
  opacity: 0;
  transition: opacity 2s ease;
}

SwitchTransition

1.核心属性:mode

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

2.子组件必须是 CSSTransition 或 Transition

3.通过 key 属性来区分不同的子组件

App.jsx

javascript 复制代码
import React, { PureComponent } from 'react'
import { SwitchTransition, CSSTransition } from 'react-transition-group'
import "./style.css"

export class App extends PureComponent {
  constructor() {
    super() 

    this.state = {
      isLogin: true
    }
  }

  render() {
    const { isLogin } = this.state

    return (
      <div>
        <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>
    )
  }
}

export default App

style.css

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

TransitionGroup

可同时管理多个 TransitionCSSTransition 组件

App.jsx

javascript 复制代码
import React, { PureComponent } from 'react'
import { TransitionGroup, CSSTransition } from "react-transition-group"
import "./style.css"

export class App extends PureComponent {
  constructor() {
    super()

    this.state = {
      books: [
        { id: 111, name: "你不知道JS", price: 99 },
        { id: 222, name: "JS高级程序设计", price: 88 },
        { id: 333, name: "Vuejs高级设计", price: 77 },
      ]
    }
  }

  addNewBook() {
    const books = [...this.state.books]
    books.push({ id: new Date().getTime(), name: "React高级程序设计", price: 99 })
    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((item, index) => {
              return (
                <CSSTransition key={item.id} classNames="book" timeout={1000}>
                  <li>
                    <span>{item.name}-{item.price}</span>
                    <button onClick={e => this.removeBook(index)}>删除</button>
                  </li>
                </CSSTransition>
              )
            })
          }
        </TransitionGroup>
        <button onClick={e => this.addNewBook()}>添加新书籍</button>
      </div>
    )
  }
}

export default App

style.css

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编写CSS方式

内联样式style

写在行内,传入一个小驼峰命名的js对象,并且可以设置动态的样式

javascript 复制代码
import React, { PureComponent } from 'react'

export class App extends PureComponent {
  constructor() {
    super()

    this.state = {
      titleSize: 30
    }
  }

  addTitleSize() {
    this.setState({ titleSize: this.state.titleSize + 2 })
  }

  render() {
    const { titleSize } = this.state

    return (
      <div>
        <button onClick={e => this.addTitleSize()}>增加titleSize</button>
        <h2 style={{color: "red", fontSize: `${titleSize}px`}}>我是标题</h2>
        <p style={{color: "blue", fontSize: "20px"}}>我是内容, 哈哈哈</p>
      </div>
    )
  }
}

export default App

CSS Module

将CSS样式封装到组件中,为每个组件生成唯一的类名,确保样式作用域仅限于当前组件,从而避免样式冲突

步骤一:创建一个名为 App.module.css 的文件

css 复制代码
.title {
  font-size: 32px;
  color: green;
}

.content {
  font-size: 22px;
  color: orange;
}

步骤二:通过 import 导入 CSS Module 文件,并使用生成的类名

javascript 复制代码
import React, { PureComponent } from 'react'
import Home from './home/Home'
import Profile from './profile/Profile'

import appStyle from "./App.module.css"

export class App extends PureComponent {
  render() {
    return (
      <div>
        <h2 className={appStyle.title}>我是标题</h2>
        <p className={appStyle.content}>我是内容, 哈哈哈哈</p>

        <Home/>
        <Profile/>
      </div>
    )
  }
}

export default App

工作原理:CSS Modules 在构建过程中会自动为每个类名生成一个唯一的哈希值

Less编写

1. 安装 Less 和相关依赖

复制代码
npm install less less-loader --save-dev

2.配置 Webpack 支持 Less

对于 Create React App 项目

由于 Create React App 默认隐藏了 Webpack 配置,可以通过 craco(Create React App Configuration Override)来修改配置:

step1:安装 cracocraco-less

复制代码
npm install @craco/craco craco-less --save-dev

step2:创建 craco.config.js 文件,并配置 Less:

javascript 复制代码
const CracoLessPlugin = require('craco-less');

module.exports = {
  plugins: [
    {
      plugin: CracoLessPlugin,
      options: {
        lessLoaderOptions: {
          lessOptions: {
            modifyVars: { '@primary-color': '#1e80ff' },
            javascriptEnabled: true,
          },
        },
      },
    },
  ],
};

step3:修改 package.json 中的脚本命令,将 react-scripts 替换为 craco

javascript 复制代码
"scripts": {
  "start": "craco start",
  "build": "craco build",
  "test": "craco test",
  "eject": "react-scripts eject"
}

3.使用 Less 编写样式

step1:定义全局变量

css 复制代码
@primaryColor: red;

.section {
  border: 1px solid @primaryColor;

  .title {
    font-size: 30px;
    color: @primaryColor;
  }

  .content {
    font-size: 20px;
    color: @primaryColor;
  }
}

step2:在组件中使用 Less

javascript 复制代码
import React, { PureComponent } from 'react'
import "./App.less"

export class App extends PureComponent {
  render() {
    return (
      <div className='app'>
        <div className='section'>
          <h2 className='title'>我是标题</h2>
          <p className='content'>我是内容, 哈哈哈</p>
        </div>
      </div>
    )
  }
}

export default App

CSS in JS

React思想中认为逻辑本身和UI是无法分离的,所有才有了JSX语法;样式也是UI的一部分,CSS-in-JS就是将样式写入到JS或TS中的方式

1.工作原理:

  • 将样式定义在 JavaScript 中,并通过动态生成的类名或内联样式直接应用于组件
  • 这种方式使得样式的作用域完全限定在组件内部,避免了全局样式冲突

2.基本使用

step1:安装styled-components:使用模板字符串定义样式

复制代码
npm i styled-components

step2:定义一个style.js文件

javascript 复制代码
import styled from "styled-components"

export const AppWrapper = styled.div`
  border: 1px solid orange;
`

step3:导入组件中

javascript 复制代码
import React, { PureComponent } from 'react'
import { AppWrapper} from "./style"

export class App extends PureComponent {
  render() {
    return (
      <AppWrapper>
          <h2 className='title'>我是标题</h2>
          <p className='content'>我是内容, 哈哈哈</p>
      </AppWrapper>
    )
  }
}

export default App

3.props接收数据

获取props需要通过${}传入一个插值函数,props会作为该函数的参数

4. attrs属性

用于传递一组额外的属性到组件中,通常与props一起使用

当传过来的有值时使用传过来的,没值时设置一个默认样式

javascript 复制代码
export const SectionWrapper = styled.div.attrs(props => ({
  tColor: props.color || "blue"
}))`
  border: 1px solid red;

  .title {
    font-size: ${props => props.size}px;
    color: ${props => props.tColor};

    &:hover {
      background-color: purple;
    }
  }
  }
`

5.styled高级特性

支持样式继承

javascript 复制代码
import styled from "styled-components";

const HYButton = styled.button`
  border: 1px solid red;
  border-radius: 5px;
`

export const HYButtonWrapper = styled(HYButton)`
  background-color: #0f0;
  color: #fff;
`

styled设置主题

可用来设置和管理主题样式

classnames库

我们在react中可借用一个第三方库classnames来动态添加某些类

step1:安装

复制代码
npm install classnames

step2:使用

javascript 复制代码
import React, { PureComponent } from 'react'
import classNames from 'classnames'

export class App extends PureComponent {
  constructor() {
    super()

    this.state = {
      isbbb: true,
      isccc: true
    }
  }

  render() {
    const { isbbb, isccc } = this.state

    const classList = ["aaa"]
    if (isbbb) classList.push("bbb")
    if (isccc) classList.push("ccc")
    const classname = classList.join(" ")

    return (
      <div>
        <h2 className={`aaa ${isbbb ? 'bbb': ''} ${isccc ? 'ccc': ''}`}>哈哈哈</h2>
        <h2 className={classname}>呵呵呵</h2>

        <h2 className={classNames("aaa", { bbb:isbbb, ccc:isccc })}>嘿嘿嘿</h2>
        <h2 className={classNames(["aaa", { bbb: isbbb, ccc: isccc }])}>嘻嘻嘻</h2>
      </div>
    )
  }
}

export default App
相关推荐
小二·18 分钟前
如何在Vue项目中封装axios
前端·javascript·vue.js
Billy Qin31 分钟前
【Mac】npm error Error: EACCES: permission denied, mkdir‘/Users/...
前端·macos·npm
好青崧1 小时前
HTML元素小卖部:表单元素 vs 表格元素选购指南
前端
饼干帅成渣1 小时前
HTML跑酷
前端·html
绿草在线1 小时前
elementplus的el-tabs路由式
前端·javascript·vue.js
知识分享小能手1 小时前
CSS3学习教程,从入门到精通, CSS3 盒子模型的详细语法知识点及案例代码(23)
前端·javascript·css·学习·css3·html5·java后端开发
Gerry-Xu2 小时前
鸿蒙篇:vp、fp、px
前端·javascript·css
东东__net2 小时前
26_ajax
前端·javascript·ajax
Riesenzahn2 小时前
怎么把项目里的webpack换成vite?
前端·javascript
Riesenzahn2 小时前
vite是如何进行热更新的?
前端·javascript