使用 CSS Modules
出现
我们日常的开发模式是组件化开发,我们希望每个组件都能作为一个独立的模块,即使是样式也应该仅在组件内部生效,不会相互影响。然而,传统的全局 CSS 往往无法满足这种需求,因为样式之间会相互干扰。为了解决这个问题,CSS Modules 提供了一个合适的解决方案。
CSS Modules
CSS Modules 是一种用于管理 CSS 样式的模块化解决方案。它解决了传统 CSS 的全局作用域、样式冲突和命名空间污染等问题,提供了局部作用域、类名转换和样式导入等功能,提高了样式的可维护性和可重用性。
核心概念
- 每个 CSS 文件都被视为一个模块,与特定的组件或模块关联。
- 在编译时,CSS Modules 将 CSS 类名转换为唯一的局部作用域类名。
- 每个组件都有自己的局部作用域,样式规则只适用于当前组件内部。
使用指南
EMP 内置了 less-loader
、postcss-loader
、sass-loader
处理 CSS 文件。你可以直接在项目中导入 Less、Sass 或 Scss 文件进行使用。
使用示例
React
在 React 中启用 CSS Modules,我们只需要使用 [name].module.css
作为样式文件名。
以下文件扩展名的样式文件将被视为 CSS Modules:
*.module.css
*.module.less
*.module.sass
*.module.scss
*.module.styl
*.module.stylus
以下是一个简单的示例:
我们将 index.tsx
文件、index.module.scss
文件放在同一文件夹。
在 index.tsx
文件中编写组件:
index.tsx
import React, { memo } from "react";
import type { FC, ReactNode } from "react";
import styles from "./index.module.scss";
interface IProps {
children?: ReactNode;
}
const MyComponent: FC<IProps> = () => {
return (
<div className={styles.container}>
<h1 className={styles.title}>Hello, CSS Modules!</h1>
</div>
);
};
export default memo(MyComponent);
在 index.module.scss
文件中编写样式:
index.module.scss
.container {
background-color: #f0f0f0;
padding: 10px;
}
.title {
font-size: 20px;
color: #333;
}
然而,当 React 组件需要添加多个类名时,我们需要将类名放在一个数组中;当我们需要动态添加/移除类名时,我们需要使用条件判断语句进行条件判断。
为了更方便地动态添加/移除类名,我们推荐使用第三方库 classnames
结合 CSS Modules 进行使用。
以下是一个简单的示例:
我们需要安装 classnames
:
在 index.tsx
文件中编写组件:
index.tsx
import React, { memo, useState } from "react";
import type { FC, ReactNode } from "react";
import styles from "./index.module.scss";
import cx from "classnames";
interface IProps {
children?: ReactNode;
isActive: boolean;
}
const MyComponent: FC<IProps> = (props) => {
const { isActive } = props;
const [curText, setCurText] = useState(1);
function changeTextStyle() {
setCurText(curText === 3 ? 1 : curText + 1);
}
return (
<div className={styles.container}>
{/* 条件判断 */}
<h1 className={cx(styles.title, { [styles.active]: isActive })}>Hello, CSS Modules!</h1>
<h2 className={cx(styles.title, isActive ? styles.active : "")}>Hello, CSS Modules!</h2>
<h3 className={cx(styles.title, isActive && styles.active)}>Hello, CSS Modules!</h3>
{/* 动态拼接 */}
<p className={cx(styles.text, styles?.[`text_${curText}`])}>这是一段文字</p>
<button onClick={changeTextStyle}>改变文字样式</button>
</div>
);
};
export default memo(MyComponent);
💡TIP:你可以自定义从 classnames
引入的名字
在 index.module.scss
文件中编写样式:
index.module.scss
.container {
padding: 10px;
background-color: #f0f0f0;
}
.title {
color: #333;
}
.active {
color: red;
}
.text_1 {
color: rgb(19, 59, 65);
}
.text_2 {
color: rgb(255, 0, 255);
}
.text_3 {
color: rgb(163, 81, 99);
}
在根组件中引入 MyComponent
组件:
App.tsx
import "./App.css";
import MyComponent from "./components/index";
const App = () => {
return (
<div className='content'>
<MyComponent isActive={false} />
</div>
);
};
export default App;
Vue
.vue
文件中的 style
标签用于定义组件的样式。默认情况下,.vue
文件中的样式是全局属性,即它们会对整个应用程序产生作用。这意味着,如果你在一个组件中定义了某个样式,它将会影响到其他组件中相同元素的样式。
然而,Vue 也提供了一种作用域样式的方式,即设置 scoped
属性。当你在 style
标签中添加了 scoped
属性后,样式将仅对当前组件起作用,不会影响其他组件中相同元素的样式。这种方式可以确保组件之间的样式相互隔离,避免样式冲突和意外的样式覆盖。
通过使用 scoped
属性,你可以在Vue组件中轻松地编写样式,而无需担心全局样式的干扰。每个组件都有其独立的样式作用域,使得组件化开发更加灵活和可维护。
同时,lang
属性可用于在 <style>
元素中指定样式代码的语言和编码规则。
以下是一个简单的示例:
创建 components
文件夹,在 MyComponent.vue
文件中编写组件:
MyComponent.vue
<template>
<div class="container">
<button class="btn">Click me</button>
</div>
</template>
<script setup lang="ts"></script>
<style lang="scss" scoped>
.container {
display: flex;
justify-content: center;
align-items: center;
}
.btn {
padding: 10px 20px;
background-color: blue;
color: white;
border: none;
border-radius: 10px;
}
</style>
在根组件中引入 MyComponent
组件:
App.vue
<template>
<div>
<MyComponent />
</div>
</template>
<script lang="ts" setup>
import MyComponent from "./components/MyComponent.vue";
</script>
<style lang="scss">
body {
padding: 10px;
}
</style>