阅读 653

React的CSS模块化

react为何要进行模块化

近期个人在开发一个小项目,然后遇到了一个极其诡异的事情,我写的CSS乱套了!!!一个小项目开发到一半了,然后发现CSS乱套了,麻了呀!

后来慢慢去分析原因,竟然发现没有进行CSS模块化导致CSS全局污染,害。 image.png

什么是CSS全局污染

当进行一个项目开发过程中,由于CSS类型定义不规范,导致存在相同类名出现样式覆盖的情况,就是CSS全局污染。简单来说,因为CSS引入的规则是引入CSS的时候后面引入的会覆盖掉前面的相同CSS样式,就像我们合并多个对象,当存在相同的key的时候,后面的对象会把前面相同key的value覆盖成自己的

情景再现

1. 我们新开一个react项目,在src下的App.js我们定义一个盒子

//app.js
import './App.css';
function App() {
  return (
    <div className="App">
      <div className="box">
        
      </div>
    </div>
  );
}

export default App;
复制代码
// App.css
.App {
  width: 100vw;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}
.box{
  width: 400px;
  height: 400px;
  background-color: red;
}

复制代码

在这里不用运行,我们也可以猜到,会出现一个400×400的红色盒子,效果如图

image.png

2. 我们在增加一个组件,然后里面也有一个盒子,200×200的蓝色盒子,放在App的盒子里面

// demo01.jsx
import './index.css'
export default function Demo01() {
    return (
        <div className="box">demo01</div>
    )
}
复制代码
// demo01.css
.box{
    width: 200px;
    height: 200px;
    background-color: blue;
}
复制代码

在这里,大家期待的肯定和我一样是这样子的

image.png 但是结果肯定会是这个样子的image.png 不信的的话我们赌一包辣条,五毛的! 好家伙到这bug就开始出来了,没事,先瞎几把分析一波

97147E90080A79695047F37CF866E361.jpg

分析个球球,样式出了问题还有比直接跑起来查html结构和CSS更快的吗!

image.png 在这里可以很清晰的看到两个div盒子,再查一下两个box盒子的css,你会发现一模一样,这不就出现了CSS全局污染了嘛

解决方案

其实这个问题解决方案还是蛮多的,目前个人了解主流的有三种

1. scoped 属性

scoped是在vue开发中使用比较多的,这边主要对react的CSS模块化进行开展(当然也可以引申到vue),但是scoped并不是很完美,在vue中scoped的思想是将样式进行私有化,但是私有化带来的缺点就是父组件的css不会对子组件进行渲染(这是我们需要的!),但是同时当你动态添加一段html的时候,也不会进行渲染!这也算是scoped的一个短板吧

2. CSS in JS

CSS in JS 的思想是利用JS对象的key:value模式,将CSS类名用key来存,里面的属性用value来存,然后使用的时候只要引入使用就可以,操作也是极其方便的!如图:

image.png

这种模式大家争论还是褒贬不一,就像吃个粽子,还有南咸北甜之说。(悄咪咪的补刀:使用起来确实蛮舒服,就是代码多了一堆堆在一起...)

3. css-loader 官方文档

终于进入今天的重头戏了,CSS的module。其实使用上和CSS in JS差不多,但是不同的是,CSS in JS 是直接在同一个文档里面写js又写css,但是css module是需要自己手动配置webpack,接下来我就教教大家怎么配置css-loader实现css模块化吧! (吐槽:前端真的太难了,C3H5只能作为基础的基础,JS要熟练还要会36个手写题,会了还要算法还要手写路由和diff,会了react/vue还要会webpack数据库计网计组Linux,孩子学麻了)

手动实现CSS模块化

1. 创建react项目

- create-react-app demo01
复制代码

2. 启动一下

- npm run start  //能跑就行(自我欺骗注释法)
复制代码

3. 暴露webpack配置

进入一个新的react项目你会发现里面肯定是有webpack在运作但是你根本看不到webpack,这时候就需要我们手动把webpack给暴露出来

在package.json里面,我们可以看到这一行(如果不是脚手架出来的项目那就自己慢慢查开发文档吧)

image.png

跑它,跑它就完事!但是如果是在git仓库里,直接跑肯定是会翻车的,因为我们在git仓库里创建这个项目的时候会自动添加额外的一个.git隐藏文件,有额外的文件跑的时候是会出现下面这种错误的!

image.png

解决的办法有两种,要么移除它,要么合并它 1. 移除 - git rm .git 2. 合并(个人比较喜欢) - git三连击 - git status - git add . - git commit 选一个操作后,然后就npm run eject,成功的时候会有三个标志,一个是执行结束绿色的提示,一个是package.json多了一堆的依赖,还有就是目录下多了一个config文件夹,里面就是我们的webpack配置。确认里面有css-loader(只要正常来都会有,没有就就装一个就好了)

image.png

4. 构建项目结构

项目结构这里我就不展开讲了,也挺简单的,可以参考egg.js脚手架出来的结构,然后再common里面放置我们的全局样式,其他地方对标src下面的pages目录建立对应的css文档,一个好的项目文档架构对开发和后期阅读维护等一系列操作时辅助极大的,清爽的文档结构,可以让你快速明白各个文件和文件夹是干嘛用的

image.png

5. 配置css-loader

进入config的对应文件,找到css-loader

image.png

接下来就开始配置我们的css-loader

在这配置之前,个人建议还是看一眼官方文档,知道各个地方要干嘛

我们配置css-loader,肯定是要区别对待的,像全局样式就要剔除出来,但是组件部分的,肯定是要进行模块化的。记住这两个小目标,就可以开始动手了!

我们主要配置的还是options,最开始是options: cssOptions的默认配置,将其修改为我们需要的样子就可以了!

第一步:开启模块化

image.png

在不同版本中这个配置也是有所不同的,大家了解这个做法就好!

既然开启了模块化,那么我们就要试试模块化引入,并且使用看看!

image.png

在过去引入我们都是直接import就可以,现在我们在引入的时候需要加上别名,并且使用方式也有点不同,用引入名.类名才可以使用!再看看我们的输出吧!

image.png

可以很明显变成了一个对象,这也是我在上面提到的CSS in JS和CSS模块化用法很相似的原因!

现在我们实现了模块化,但是这样子所有的CSS文件都会被模块化,接下来我们就要进行文件分类,指定的全局样式文件不进行模块化就好了!

第二步:排除指定文件

先添加一个函数,返回当前路径的上一级,即项目根目录

排除根目录下的node_modules和全局样式文件,node_modules中我们可能会使用第三方UI,所以需要排除,全局样式我们根目录下引入后默认应用到全局,也是需要排除的!配置的时候位置大家一定要找准,否则项目也会直接跑不起来

image.png

刚刚我们把不需要配置的地方挑了出来,接下来我们就要应用上

image.png

成果展示

接下来我们就可以看看我们的成功了 首先我们得全局样式是直接引入的

image.png

而在组件内我们是使用了模块化

image.png

在同时存在两个两个box类的情况下,还能出现我们期待的效果嘛?

image.png

修改几个参数就可以实现CSS模块化,一次配置,一直受用,真香!(webpack在不同版本会有所差异,可能部分小伙伴跟着跑会出先一点点小差错,但是基本方式是ok的,大家耐心点找到各个要配置的地方就可以!)

我是江河,前端实习生一枚,正在准备实习,欢迎各位大佬滴滴,文章如有不正之处敬请斧正!

文章分类
阅读
文章标签