在React项目中使用 CSS Module

穷尽一生,一事无成是常态,更是这个世界上99%的人真实写照

大家好,我是柒八九

前言

就在前几天,写了一篇CSS 20大酷刑,然后看后台数据,反馈还是挺好的,看来大家还是对这个最熟悉的陌生人 ,有种食之无味,弃之可惜 的感觉。在上篇中,我们就说过,由于CSS庞杂的体系和令人眼花缭乱的属性,总是让人望而却步 。但是,它也是我们翻身农奴做主人,势必要翻过的四座大山之一 CSS/Html/JavaScript/WebAsssembly。(自认为,WebAssembly也会成为一座我们需要逾越的大山,有关它的介绍,可以看我们之前写的浏览器第四种语言-WebAssembly)

而,今天我们讲点轻松的东西,内容有点少,可以在茶余饭后,当个配菜来品尝

React中,CSS模块(CSS Module)只是一个.css文件,类似于JavaScript中的局部变量 。它减少了React样式的全局作用域。此外,它是一种通过生成一个随机字符串作为className名称并添加一个唯一的哈希来使每个className都唯一的工具,从而防止和全局作用域冲突。我们可以使用CSS模块来防止CSS类的命名冲突。只需将CSS模块文件导入到我们的组件中,就可以在各种CSS文件中使用相同的CSS类

任何CSS文件都可以安全地更新,而无需担心会影响其他页面,因为它只具有局部作用域,只能影响使用了更改后的CSS模块文件的其他组件。当使用CSS模块在浏览器中呈现时,它会生成随机的CSS类,只有在仔细检查页面时才可见。

你能所学到的知识点

  1. 前置知识点
  2. CSS模块的红与黑
  3. CSS模块使用语法
  4. 创建一下CSS模块
  5. 在React中使用 CSS 模块
  6. 全局 CSS

好了,天不早了,干点正事哇。


1. 前置知识点

前置知识点 ,只是做一个概念的介绍,不会做深度解释。因为,这些概念在下面文章中会有出现,为了让行文更加的顺畅,所以将本该在文内的概念解释放到前面来。如果大家对这些概念熟悉,可以直接忽略

CSS-in-JS简介

CSS-in-JS 是一种前端开发方法,它将样式表达式嵌入到 JavaScript 中,以便更好地管理和组织样式。这种方法的主要思想是将组件的样式与组件本身紧密耦合在一起,以提高可维护性、可读性和复用性CSS-in-JS 有许多不同的库和工具,每个都有自己的语法和特性,但核心思想是相似的。

以下是 CSS-in-JS 的一些主要特点和优势:

  1. 组件化样式CSS-in-JS 允许我们将样式与组件一起定义,将它们封装在一起。这使得代码更具可读性,因为我们可以在组件的定义中直接查看和理解样式。

  2. 动态样式 :与传统的 CSS 不同,CSS-in-JS 允许我们根据组件的状态或属性来动态生成样式。这使得样式更加灵活,能够根据应用的不同情况进行调整。

  3. 自动前缀 :许多 CSS-in-JS 库会自动添加浏览器前缀,以确保样式在不同浏览器中都能正常工作。

  4. 组件级别作用域样式是组件级别的,不会与其他组件的样式冲突,从而避免全局样式表的问题。

  5. 性能优化 :某些 CSS-in-JS 库会使用类似于样式提取style extraction)的技术,将样式提取为单独的 CSS 文件,以提高性能。

  6. 可维护性:将样式与组件紧密结合使得代码更易于维护,因为我们可以在同一个文件中查找组件的样式定义,而不必在多个文件之间跳转。

像比较常见的库有

由于它们的语法还有使用方式相差无几,所以我们就挑一个比较常见的库进行演示。如果想了解其它的使用方式,可以根据上面链接,直接访问其官网。

Styled Component

下面展示了如何使用 styled-components 创建一个简单的按钮组件:

首先,我们需要安装 styled-components

bash 复制代码
npm install styled-components

然后,我们可以创建一个按钮组件:

jsx 复制代码
// 导入 styled-components 库
import styled from 'styled-components';

// 创建一个样式化的按钮组件
const Button = styled.button`
  background-color: #007bff;
  color: #fff;
  border: none;
  padding: 10px 20px;
  cursor: pointer;

  &:hover {
    background-color: #0056b3;
  }
`;

// 在我们的应用中使用这个按钮组件
function App() {
  return (
    <div>
      <h1>前端柒八九</h1>
      <Button onClick={() => alert('Helllo, 骚年')}>关注走一波</Button>
    </div>
  );
}

export default App;

在上面的示例中,我们导入 styled-components 库,然后使用 styled.button 创建一个按钮组件。我们使用模板字符串定义了按钮的样式,包括背景颜色、文字颜色 等。&:hover 是一个伪类选择器,用于定义按钮的鼠标悬停样式。

最后,在应用中使用这个按钮组件,就像使用普通的 React 组件一样。


2. CSS模块的红与黑

优点:

  • 通过使用CSS模块,可以避免CSS类的命名空间冲突多个CSS文件可以包含相同的CSS类
  • CSS模块中,我们可以将类发送到多个组件。
  • 使用CSS模块的一个关键优点是,我们可以放心地编辑任何CSS文件,而不必担心它会影响其他模块。
  • 使用CSS模块创建可移植可重用的CSS文件。不再需要担心规则会影响其他组件的样式或选择器名称冲突。
  • 尽管项目复杂,但CSS模块可以使我们的代码看起来整洁,以便其他开发人员可以阅读和理解它。

缺点:

  • 在将样式集成到项目中时,必须将样式包含为带有点号方括号表示法的对象。
  • Styled Components不同,CSS模块不接受props

那么,为什么要使用CSS模块呢?

  • 在使用CSS模块时,我们可以确保给定组件的每个样式都位于一个位置,并且仅适用于导入它的组件。
  • 借助CSS模块和默认的局部作用域概念,可以避免全局作用域的问题。
  • 在编写样式时,我们总是怕和别人起了相同的类名影响现有的业务,总是畏首畏尾,战战兢兢的编写自己的样式代码。

3. CSS模块使用语法

现在属于SPA的天下,那在使用框架时候就绕不开,模块化构建工具(如WebpackviteRspack)来管理样式。

下面我们简单分别介绍一下,它们对CSS模块的支持程度。

当我们安装create-React-app时,React会为我们处理一切;因此,我们目前不需要为Webpack配置CSS模块

在使用CSS模块时,不需要额外的代码或添加到CSS模块的第三方代码。我们只需要将CSS文件的名称更改为[文件名].Modules.css;我们可以用任何其他名称替代[文件名]。在使用CSS模块时,我们必须使用import关键字将文件导入到特定组件中。在将CSS模块集成到我们的React项目中时,我们必须指定类,就像在标准JavaScript中使用点符号或方括号语法访问对象的属性一样

使用点符号表示法:

jsx 复制代码
<div className={classes.parent_div}></div>

如果我们的CSS类包含连字符,应使用方括号表示法

jsx 复制代码
<div className={classes["parent-div"]}></div>

我们可以组合样式:

jsx 复制代码
const buttonClasses = classes.myBtn + " " + classes.extra_classes;

这些是纯粹的普通JavaScript对象的基本概念。

Vite天然支持CSS模块 Rspack也天然支持CSS模块


4. 创建一下CSS模块

Styled ComponentEmotionstyled-jsx等CSS库现在都广泛使用。但是,我认为CSS模块是会在未来大放异彩 ,特别是全局范围可重用性 ,这使得我们以后写样式时,不用如履薄冰。CSS模块越来越广泛地用于在特定组件中本地描述样式并避免全局作用域。

让我们从一个简单的项目开始。我们将创建一个[文件名].module.css文件。我们将导入我们的[文件名].module.css的组件如下所示。

TypeScript用户必须添加一个.d.ts文件;在这种情况下,我们将创建[文件名].module.css.d.ts"。

tsx 复制代码
// [fileName].module.css.d.ts
export const styles: string;
export const someStyles: string;
export const moreStyles: string;

这个文件定义了一些CSS模块中的样式类,可以在组件中使用。

[fileName].module.css的内容如下所示:

css 复制代码
.container {
    width: 500px;
    padding: 20px;
    background-color: white;
    box-shadow: 17px 18px 10px #767676;
    text-align: center;
    line-height: 3;
    margin: 20px;
}

.border_radius {
    border-radius: 40px;
}

.counter-title {
    color: cornflowerblue;
    font-family: cursive;
    font-weight: bolder;
}

.container button {
    background-color: cornflowerblue;
    padding: 15px 20px;
    border-radius: 10px;
    color: white;
    border: none;
    outline: none;
}

要将CSS模块的样式表导入到组件中,最好在[classes][styles]前缀下导入它。样式或类的前缀并不是强制性的,但我们将使用类以符合最佳实践。要使用样式,请确保路径包含./[fileName].module.css对应的文件。

jsx 复制代码
import classes from "./Styles.module.css";

5. 在React中使用 CSS 模块

在使用CSS 模块时,可以将样式写在CSS文件中,然后使用上面所示的点号方括号表示法来引用导入的CSS模块。在下面的代码中,我们演示了如何在React组件中利用CSS Modules

函数组件

在React函数组件中,我们将使用CSS Modules。下面的代码增加了计数器的值并使用useState在将要创建的FunctionCounter.js组件中。

jsx 复制代码
import React, { useState } from "react";
import classes from "./Styles.module.css";

const FunctionCounter = () => {
    const [counter, setCounter] = useState(0);

    const handleClick = () => {
        setCounter(counter + 2);
    };

    return (
      <>
        <div className={classes.container}>
            <p className={classes["paragraph-text"]}>前端柒八九</p>
            <h2 className={classes["counter-title"]}>{counter}</h2>
            <button onClick={handleClick}>数字加2</button>
        </div>
      </>
    );
};

export default FunctionCounter;

这个组件使用了从CSS模块导入的样式类,并且在点击按钮时会增加计数器的值。这样,我们可以在React函数组件中利用CSS模块来管理样式。

类组件

我们将看到一个使用CSS模块的类组件。我们将创建一个名为ClassCounter.js的Class组件。下面的代码会将计数值增加2。

jsx 复制代码
import React from "react";
import classes from "./Styles.module.css";

class ClassCounter extends React.Component {
    constructor() {
        super();
        this.state = { counter: 0 };
        // 这个绑定是必要的,以使`this`在回调中正常工作
        this.handleClick = this.handleClick.bind(this);
    }

    handleClick = () => {
        this.setState({
            counter: this.state.counter + 1,
        });
    };

    render() {
        return (
            <div className={`${classes.container} ${classes.border_radius}`}>
                <p className={classes["paragraph-text"]}>前端柒八九</p>
                <h2 className={classes["counter-title"]}>{this.state.counter}</h2>
                <button onClick={this.handleClick}>数字加1</button>
            </div>
        );
    }
}

export default ClassCounter;

最后,让我们看一下App.js组件。我们将在App.js组件中导入FunctionCounter.jsClassCounter.js组件。

jsx 复制代码
import React from "react";
import ClassCounter from "./ClassCounter";
import FunctionCounter from "./FunctionCounter";

const App = () => {
    return (
        <div>
            <FunctionCounter />
            <br />
            <ClassCounter />
        </div>
    );
};

export default App;

以下是我们的CSS模块中的ClassFunction组件的输出。

并且我们在浏览器中进行元素审查时,可以看到指定元素中的class使用从CSS模块获取的哈希值。


6. 全局 CSS

CSS模块并不禁止使用全局CSS。我们可以使用与导入ES6相同的方法导入样式表。

jsx 复制代码
import './App.css'

此外,我们可以使用关键字global来更改类的范围,以防止CSS模块修改它。

css 复制代码
:global(.class) {
    color:red;
}

:global .button {}

以下是上面代码的解释:

  1. :global(.class):这是一个CSS Modules中的语法,:global 告诉CSS模块不要将此类名限制在模块范围内,而是将其视为全局CSS类名。这意味着任何地方都可以使用 .class 类名,而不受模块化的限制。

    css 复制代码
    /* 在CSS模块中 */
    .class {
      color:red;
    }

    在这里,.class 类名的样式会在整个应用程序中全局生效。

  2. :global .button:这也是使用:global将样式声明为全局的示例。.button 类名可以在整个应用程序中任何地方使用,不受模块化的限制。

    css 复制代码
    /* 在CSS模块中 */
    .button {
      /* 样式规则 */
    }

    在这里,.button 类名的样式也会在整个应用程序中全局生效。

需要注意的是,:global 是一种逃逸机制 ,用于在CSS模块中定义全局样式。通常情况下,CSS Modules的目标是将样式局部化,以避免全局污染和冲突。但有些情况下,我们可能需要使用全局样式,这时可以使用:global


7. 多个 CSS模块混合使用

CSS模块不限制使用多个类;我们可以按照以下方式使用CSS模块来添加多个类:

html 复制代码
<div className={`${classes.container} ${classes.border_radius}`}></div>


function Footer( props) {
    return (
        <div className={styles.section}>
            <div className={`${styles.description} ${styles.black}`}>
                <p>CSS模块的使用说明</p>
            </div>
        </div>
    );
}

8. 伪类选择器

伪类选择器用于选择处于特定状态的元素。由于CSS模块通过为我们的元素添加类来工作,因此添加伪类选择器非常简单。

jsx 复制代码
// Button.module.css
.button:hover {background-color;: }
.button:disabled {color: #ddd}
.button:active {color: grau}

//============
import classes from "./Button.module.css";
import React, { Component } from "react";
export default class Text extends Component {
    render() {
    return <button className={classes.button}>关注我,给你一个不一样的技术分享</button>;
    }
}

后记

分享是一种态度

参考资料:

  1. Styled Component
  2. Emotion
  3. css-modules
  4. vite-css-module
  5. rspack-css-module

全文完,既然看到这里了,如果觉得不错,随手点个赞和"在看"吧。

相关推荐
半开半落1 分钟前
nuxt3安装pinia报错500[vite-node] [ERR_LOAD_URL]问题解决
前端·javascript·vue.js·nuxt
理想不理想v29 分钟前
vue经典前端面试题
前端·javascript·vue.js
不收藏找不到我30 分钟前
浏览器交互事件汇总
前端·交互
YBN娜43 分钟前
Vue实现登录功能
前端·javascript·vue.js
阳光开朗大男孩 = ̄ω ̄=43 分钟前
CSS——选择器、PxCook软件、盒子模型
前端·javascript·css
minDuck1 小时前
ruoyi-vue集成tianai-captcha验证码
java·前端·vue.js
小政爱学习!1 小时前
封装axios、环境变量、api解耦、解决跨域、全局组件注入
开发语言·前端·javascript
魏大帅。1 小时前
Axios 的 responseType 属性详解及 Blob 与 ArrayBuffer 解析
前端·javascript·ajax
花花鱼1 小时前
vue3 基于element-plus进行的一个可拖动改变导航与内容区域大小的简单方法
前端·javascript·elementui
k09331 小时前
sourceTree回滚版本到某次提交
开发语言·前端·javascript