react 动画_样式处理

动画

在日常开发中,页面切换时的转场动画是比较基础的一个场景

当一个组件在显示与消失过程中存在过渡动画,可以很好的增加用户的体验

在 react中实现过渡动画效果会有很多种选择,如 react-transition-group, react-motion,Animated,以及原生的 CSS 都能完成切换动画

在 react 中,react-transition-group 是一种很好的解决方案,其为元素添加 enter, enter-active, exit,exit-active 这一系列勾子

可以帮助我们方便的实现组件的入场和离场动画其主要提供了三个主要的组件:

  • CSSTransition:在前端开发中,结合 CSS 来完成过渡动画效果
  • SwitchTransition:两个组件显示和隐藏切换时,使用该组件
  • TransitionGroup:将多个动画组件包裹在其中,一般用于列表中元素的动画

基本概念

  • 在开发中,我们想要给一个组件的显示和消失添加某种过渡动画,这样可以很好的增加用户体验

  • 当然,我们可以通过原生的CSS来实现这些过渡动画,但是React社区为我们提供了react-transition-group用来完成过渡动画

  • React曾为开发者提供过动画插件 react-addons-css-transition-group,后由社区维护,形成了现在的 react-transition-group

  • 这个库可以帮助我们方便的实现组件的 入场 和 离场 动画,使用时需要进行额外的安装

    npm

    npm install react-transition-group --save

    yarn

    yarn add react-transition-group

react-transition-group本身非常小,不会为我们应用程序增加过多的负担

react-transition-group主要组件:

◼ Transition

 该组件是一个和平台无关的组件(不一定要结合CSS);

 在前端开发中,我们一般是结合CSS来完成样式,所以比较常用的是CSSTransition;

◼ CSSTransition

 在前端开发中,通常使用CSSTransition来完成过渡动画效果

◼ SwitchTransition

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

◼ TransitionGroup

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

CSSTransition使用

基本结构

  • CSSTransition是基于Transition组件构建的:
  • CSSTransition执行过程中,有三个状态:appear、enter、exit;
  • 它们有三种状态,需要定义对应的CSS样式:

 第一类,开始状态:对应的类是-appear、-enter、exit;

 第二类:执行动画:对应的类是-appear-active、-enter-active、-exit-active;

 第三类:执行结束:对应的类是-appear-done、-enter-done、-exit-done;

常见的属性设置

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:

 过渡动画的时间

appear:

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

unmountOnExit:退出后卸载组件

其他属性可以参考官网来学习:

https://reactcommunity.org/react-transition-group/transition

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

 onEnter:在进入动画之前被触发;

 onEntering:在应用进入动画时被触发;

 onEntered:在应用进入动画结束后被触发;

 onExit:在离开动画之前被触发;

 onExiting:在应用离开动画时被触发;

 onExited:在应用离开动画结束后被触发;

nodeRef

 用于在严格模式下,过期报错问题

Index.jsx

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

解决措施:

Demo.jsx

import React, { PureComponent } from 'react'
import { CSSTransition } from "react-transition-group"
import '../style/style.css'

export class classHello extends PureComponent {
  constructor() {
    super()
    this.state = {
      isShowTitle: true
    }
    
    // 解决严格模式下由于该css插件里的某些方法或者API由于过期报错问题
    this.sectionRef = createRef();
  }

  render() {
    const { isShowTitle } = this.state
    return (
      <div>
       {/** {isShowTitle && <h2>classHello</h2>} */}
        <CSSTransition 
        	nodeRef={this.sectionRef}
        
          in={isShowTitle} 
          classNames="show"
          unmountOnExit={true}
          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("执行离开结束")}
        >
          <h2 ref={this.sectionRef}>classHello</h2>
        </CSSTransition>
        <button onClick={e => this.setState({isShowTitle: !isShowTitle})}>切换</button>
      </div>
    )
  }
}

export default classHello

或者直接关闭(注释)index.jsx里的严格模式

import React from 'react'
import ReactDOM from 'react-dom/client'
import './index.css'
import App from './App'
import reportWebVitals from './reportWebVitals'

const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
  // <React.StrictMode>
  //   <App />
  // </React.StrictMode>
  <App />
)

reportWebVitals()

演示示例

unmountOnExit={true}   timeout={2000}
// 以上属性是必须要写的,不然会报警告

import React, { PureComponent } from 'react'
import { CSSTransition } from "react-transition-group"
import '../style/style.css'

export class classHello extends PureComponent {
  constructor() {
    super()
    this.state = {
      isShowTitle: true
    }
  }

  render() {
    const { isShowTitle } = this.state
    return (
      <div>
       {/** {isShowTitle && <h2>classHello</h2>} */}
        <CSSTransition 
          in={isShowTitle} 
          classNames="show"
          unmountOnExit={true}
          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("执行离开结束")}
        >
          <h2>classHello</h2>
        </CSSTransition>
        <button onClick={e => this.setState({isShowTitle: !isShowTitle})}>切换</button>
      </div>
    )
  }
}

export default classHello

style.css

/* 进入动画 */
/* .show-appear {
  transform: translateX(-150px);
}

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

/*进入动画初识状态、真正进入状态*/
.show-appear, .show-enter {
  opacity: 0;
}

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




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

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

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属性;

演示示例

/* 进入初始状态 */
.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;
}

import React, { PureComponent } from 'react'
import { CSSTransition, SwitchTransition } from "react-transition-group"
import '../style/style.css'

export class classHello 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 classHello

TransitionGroup

当我们有一组动画时,需要将这些CSSTransition放入到一个TransitionGroup中来完成动画:

演示示例

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

import React, { PureComponent } from 'react'
import { CSSTransition, TransitionGroup } from "react-transition-group"
import '../style/style.css'

export class classHello 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 classHello

样式处理

概述

前面说过,整个前端已经是组件化的天下:

  • 而CSS的设计就不是为组件化而生的,所以在目前组件化的框架中都在需要一种合适的CSS解决方案

在组件化中选择合适的CSS解决方案应该符合以下条件:

 可以编写局部css:css具备自己的局部作用域,不会随意污染其他组件内的元素;

 可以编写动态的css:可以获取当前组件的一些状态,根据状态的变化生成不同的css样式;

 支持所有的css特性:伪类、动画、媒体查询等;

 编写起来简洁方便、最好符合一贯的css风格特点;

 等等...

事实上,css一直是React的痛点,也是被很多开发者吐槽、诟病的一个点

在这一点上,Vue做的要好于React:

 Vue通过在.vue文件中编写 <style><style> 标签来编写自己的样式;

 通过是否添加 scoped 属性来决定编写的样式是全局有效还是局部有效;

 通过 lang 属性来设置你喜欢的 less、sass等预处理器;

 通过内联样式风格的方式来根据最新状态设置和改变css;

 等等...

Vue在CSS上虽然不能称之为完美,但是已经足够简洁、自然、方便了,至少统一的样式风格不会出现多个开发人员、多个项目采用不一样的样式风格

相比而言,React官方并没有给出在React中统一的样式风格:

 由此,从普通的css,到css modules,再到css in js,有几十种不同的解决方案,上百个不同的库;

 大家一致在寻找最好的或者说最适合自己的CSS方案,但是到目前为止也没有统一的方案;

组件式开发选择合适的 css 解决方案尤为重要

通常会遵循以下规则:

常见的 CSS引入方式有以下:

行内样式-style

基本概念

内联样式是官方推荐的一种css样式的写法:

 style 接受一个采用小驼峰命名属性的 JavaScript 对象,而不是 CSS 字符串;

 并且可以引用state中的状态来设置相关的样式;

内联样式的优点:

 1.内联样式, 样式之间不会有冲突

 2.可以动态获取当前state中的状态

内联样式的缺点:

 1.写法上都需要使用驼峰标识

 2.某些样式没有提示

 3.大量的样式, 代码混乱

 4.某些样式无法编写(比如伪类/伪元素)

所以官方依然是希望内联合适和普通的css来结合编写;

使用示例

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

或者如下写法:

注意:

  • 行内样式写法style={``{key: value}}
  • 第一层{}:嵌入jsx表达式
  • 第二层{}:代表js的对象
  • 在style样式中,如果样式带有横岗-,应使用小驼峰的方式去书写

外部样式

基本概念

普通的css我们通常会编写到一个单独的文件,之后再进行引入。

这样的编写方式和普通的网页开发中编写方式是一致的:

 如果我们按照普通的网页标准去编写,那么也不会有太大的问题;

 但是组件化开发中我们总是希望组件是一个独立的模块,即便是样式也只是在自己内部生效,不会相互影响;

 但是普通的css都属于全局的css,样式之间会相互影响;

这种编写方式最大的问题是样式之间会相互层叠掉;

使用示例

示例1:

  1. 创建css文件
    App.css

    .color {
    color: red;
    }

    .bg-color {
    background-color: blue;
    }

  2. 在App.js引入样式

    import './App.css';

  3. 使用样式

    import './App.css';

    let title = 'hahaha'

    function App() {
    return (


    {title}

    );
    }

    export default App;

注意:绑定class样式时应该使用className,不要使用class,因为class是js中的关键字。

示例2:

// 导入样式
import './base.css'
const dv = <div className="title">style样式</div>

base.css样式文件

.title {
  text-align: center;
  color: red;
  background-color: pink;
}

示例3:

const list = [
  { id: 1, name: "刘德华", content: "给我一杯忘情水" },
  { id: 2, name: "五月天", content: "不打扰,是我的温柔" },
  { id: 3, name: "毛不易", content: "像我这样优秀的人" }
];

参考示例:

App.js

import './base.css'

const list = [{
  id: 1,
  name: "刘德华",
  content: "给我一杯忘情水"
},
{
  id: 2,
  name: "五月天",
  content: "不打扰,是我的温柔"
},
{
  id: 3,
  name: "毛不易",
  content: "像我这样优秀的人"
}
];

function render() {
  if(list.length === 0){
      return <div>暂无数据</div>;
  }
  return (
      <div>
          <ul>
              {
                  list.map(item => (
                      <li style={{listStyle: 'none'}} key={item.id}>
                          <h3>评论人:{item.name}</h3>
                          <p className='text_content'>评论内容:{item.content}</p>
                      </li>
              ))
              }
          </ul>
      </div>
  )
}

function App() {
  return (
    <div>{render()}</div>
  )
}

export default App

以上这种方式存在不好的地方在于样式是全局生效,样式之间会互相影响

css modules

css modules并不是React特有的解决方案,而是所有使用了类似于webpack配置的环境下都可以使用的。

 如果在其他项目中使用它,那么我们需要自己来进行配置,比如配置webpack.config.js中的modules: true等。

React的脚手架已经内置了css modules的配置:

 .css/.less/.scss 等样式文件都需要修改成 .module.css/.module.less/.module.scss 等;

 之后就可以引用并且进行使用了;

css modules确实解决了局部作用域的问题, 将 css文件作为一个模块引入,这个模块中的所有 css,只作用于当前组件。不会影响当前组件的后代组件,也是很多人喜欢在React中使用的一种方案。

但是这种方案也有自己的缺陷:

 引用的类名,不能使用连接符(.home-title),在JavaScript中是不识别的;

// base.css
.home-title {
	color: red;
}


// App/jsx
import appStyle from "./App.module.css"
<div className={appStyle.home-title}></div> // 以上这种写法是不支持的,在js里会报错

 所有的className都必须使用{style.className} 的形式来编写;

 不方便动态来修改某些样式,依然需要使用内联样式的方式;

如果你觉得上面的缺陷还算OK,那么你在开发中完全可以选择使用css modules来编写,并且也是在React中很受欢迎的一种方式

app.module.css

.title {
  font-size: 20px;
  font-weight: 700;
  color: red;
}

App.jsx

import React, { PureComponent } from 'react'

import appStyle from '../style/app.module.css'

export class classHello extends PureComponent {
  render() {
    return (
      <div className={appStyle.title}>classHello</div>
    )
  }
}

export default classHello

CSS in JS-推荐

CsS-in-JS,是指一种模式,其中 CSS由 JavaScript 生成而不是在外部文件中定义此功能并不是 React 的一部分,而是由第三方库提供,例如:

下面主要看看 styled-components 的基本使用

可在 VsCode 里安装 styled-components 插件,就会有提示了当输入代码的时候

本质是通过函数的调用,最终创建出一个组件:

  • 这个组件会被自动添加上一个不重复的class
  • styled-components会给该class添加相关的样式

概述

官方文档也有提到过CSS in JS这种方案:

 "CSS-in-JS" 是指一种模式,其中 CSS 由 JavaScript 生成而不是在外部文件中定义;

 注意此功能并不是 React 的一部分,而是由第三方库提供;

 React 对样式如何定义并没有明确态度;

在传统的前端开发中,我们通常会将结构(HTML)、样式(CSS)、逻辑(JavaScript)进行分离。

 但是在前面的学习中,我们就提到过,React的思想中认为逻辑本身和UI是无法分离的,所以才会有了JSX的语法。

 **样式呢?**样式也是属于UI的一部分;

 事实上CSS-in-JS的模式就是一种将样式(CSS)也写入到JavaScript中的方式,并且可以方便的使用JavaScript的状态;

 所以React有被人称之为 All in JS;

当然,这种开发的方式也受到了很多的批评:

 Stop using CSS in JavaScript for web development

Stop using CSS in JavaScript for web development | HackerNoon

批评声音虽然有,但是在我们看来很多优秀的CSS-in-JS的库依然非常强大、方便:

 CSS-in-JS通过JavaScript来为CSS赋予一些能力,包括类似于CSS预处理器一样的样式嵌套、函数定义、逻辑复用、动态修改状态等等;

 虽然CSS预处理器也具备某些能力,但是获取动态状态依然是一个不好处理的点;

 所以,目前可以说CSS-in-JS是React编写CSS最为受欢迎的一种解决方案;

目前比较流行的CSS-in-JS的库有哪些呢?

 styled-components

 emotion

 glamorous

目前可以说styled-components依然是社区最流行的CSS-in-JS库,所以我们以styled-components的讲解为主;

安装styled-components:

yarn add styled-components
# 或者
npm install styled-components

可参考:https://www.npmjs.com/package/styled-components

ES6中增加了模板字符串的语法,这个对于很多人来说都会使用。

但是模板字符串还有另外一种用法:标签模板字符串(Tagged Template Literals)

我们一起来看一个普通的JavaScript的函数:

 正常情况下,我们都是通过 函数名() 方式来进行调用的,其实函数还有另外一种调用方式:

如果我们在调用的时候插入其他的变量:

 模板字符串被拆分了;

 第一个元素是数组,是被模块字符串拆分的字符串组合;

 后面的元素是一个个模块字符串传入的内容;

// 标签模板字符串
// 1. 基本使用
const age = 14
console.log(`age is ${age}`);


// 2. 标签模板字符串
function foo(...args) {
  console.log(args);
}

// foo`` // 直接调用函数
foo`my age is ${age}` // 调用函数并传参

在styled component中,就是通过这种方式来解析模块字符串,最终生成我们想要的样式的

基本使用

styled-components的本质是通过函数的调用,最终创建出一个组件:

 这个组件会被自动添加上一个不重复的class;

 styled-components会给该class添加相关的样式;

另外,它支持类似于CSS预处理器一样的样式嵌套:

 支持直接子代选择器或后代选择器,并且直接编写样式;

 可以通过&符号获取当前元素;

 支持伪类选择器、伪元素等;

示例:

import styled from 'styled-components'

export const AppWrapper = styled.div`
  .section {
    border: 1px solid #eee;
    width: 500px;
    padding: 20px;
    .title {
      color: blue;
      &:hover {
        background-color: purple;
      }
    }
    .content {
      font-size: 25px;
    }
  }
  .footer {
    margin-top: 20px;
    padding: 10px;
    width: 500px;
    border: 1px solid pink;
  }
`

import React, { PureComponent } from 'react'

import { AppWrapper } from '../style/style.js'
export class classHello extends PureComponent {
  render() {
    return (
      <AppWrapper>
        <div className="section">
          <h2 className="title">标题</h2>
          <div className="content">内容区域</div>
        </div>

        <div className="footer">
          <div>免责声明</div>
          <div>版权声明</div>
        </div>
      </AppWrapper>
    )
  }
}

export default classHello

props、attrs属性

props可以被传递给styled组件

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

 这种方式可以有效的解决动态样式的问题;

添加attrs属性

 添加默认值,不传的时候显示默认值

variable.js

export const primaryColor = '#ff8800';
export const secondPrimary = '#ff7788';

export const smallSize = '12px'
export const middleSize = '14px'
export const largeSize = '16px'

import styled from 'styled-components'
import * as vars from './variable'

// 默认值写法1--接收传递进来的数据
// export const AppWrapper = styled.div.attrs({
//   tColor: (props => props.color) || 'blue'
// })``


// 默认值写法2--接收传递进来的数据
//export const AppWrapper = styled.div.attrs(props => {
//  return {
//    tColor: props.color || 'blue'
//  }
//})``

export const AppWrapper = styled.div.attrs(props => ({
  tColor: props.color || 'blue',
}))
`
  .section {
    border: 1px solid #eee;
    width: 500px;
    padding: 20px;
    .title {
      color: ${props => props.tColor};
      font-size: ${props => props.size}px;
      &:hover {
        background-color: purple;
      }
    }
    .content {
      font-size: ${vars.largeSize};
      color: ${vars.primaryColor};
    }
  }
  .footer {
    margin-top: 20px;
    padding: 10px;
    width: 500px;
    border: 1px solid pink;
  }
`

import React, { PureComponent } from 'react'

import { AppWrapper } from '../style/style.js'
export class classHello extends PureComponent {
  constructor(){
    super()
    this.state = {
      size: 25,
      color: "orange"
    }
  }

  render() {
    const { size, color } = this.state

    return (
      // 将 size 和 color 传递给了 AppWrapper 组件
      <AppWrapper size={size} color={color}>
        <div className="section">
          <h2 className="title">标题</h2>
          <div className="content">内容区域</div>
          <button onClick={e => this.setState({color: 'red'})}>修改颜色</button>
        </div>

        <div className="footer">
          <div>免责声明</div>
          <div>版权声明</div>
        </div>
      </AppWrapper>
    )
  }
}

export default classHello

高级特性

样式的继承
import styled from 'styled-components'

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

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

export const HomeWrapper = styled.div`
`

import React, { PureComponent } from 'react'

import { HomeWrapper, LwjButtonWrapper } from '../style/home'
export class Home extends PureComponent {
  render() {
    return (
      <HomeWrapper>
        <LwjButtonWrapper>按钮</LwjButtonWrapper>
      </HomeWrapper>
    )
  }
}

export default Home
设置主题

index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

import { ThemeProvider } from 'styled-components';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <ThemeProvider theme = {{color: 'purple', size: '50px'}}>
    <App />
  </ThemeProvider>
);

reportWebVitals();

Home.js

import styled from 'styled-components'

export const HomeWrapper = styled.div`
  .top {
    .banner {
      font-size: ${props => props.theme.size};
    }
  }
  .bottom {
    .title {
      color: ${props => props.theme.color};
    }
    ul {
      li {
        color: blue;
      }
    }
  }
`

Home.jsx

import React, { PureComponent } from 'react'

import { HomeWrapper } from '../style/fun'

export class funHello extends PureComponent {
  render() {
    return (
      <HomeWrapper>
        <div className="top">
          <div className="banner">bannercontent</div>
        </div>
        <div className="bottom">
          <h2 className="title">标题</h2>
          <ul>
            <li>商品列表1</li>
            <li>商品列表2</li>
          </ul>
        </div>
      </HomeWrapper>
    )
  }
}

export default funHello

classnames库

基本概念

安装:npm install classnames

使用示例

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>

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

export default App

总结

  • JSX是React的核心内容
  • JSX表示在JS代码中书写HTML结构,是React声明式的体现
  • 使用JSX配合嵌入的JS表达式,条件渲染,列表渲染,可以渲染任意的UI结构
  • 结果使用className和style的方式给JSX添加样式
  • React完全利用JS的语言自身的能力来编写UI,而不是造轮子增强HTML的功能。(对比VUE)

至于使用 react 用哪种方案引入 Css,并没有一个绝对的答案,可以根据各自情况选择合适的方案

相关推荐
GIS程序媛—椰子11 分钟前
【Vue 全家桶】7、Vue UI组件库(更新中)
前端·vue.js
DogEgg_00117 分钟前
前端八股文(一)HTML 持续更新中。。。
前端·html
ZL不懂前端20 分钟前
Content Security Policy (CSP)
前端·javascript·面试
木舟100924 分钟前
ffmpeg重复回听音频流,时长叠加问题
前端
王大锤439134 分钟前
golang通用后台管理系统07(后台与若依前端对接)
开发语言·前端·golang
我血条子呢1 小时前
[Vue]防止路由重复跳转
前端·javascript·vue.js
黎金安1 小时前
前端第二次作业
前端·css·css3
啦啦右一1 小时前
前端 | MYTED单篇TED词汇学习功能优化
前端·学习
半开半落1 小时前
nuxt3安装pinia报错500[vite-node] [ERR_LOAD_URL]问题解决
前端·javascript·vue.js·nuxt