React CSS 终极指南:从行内样式到模块化,打造完美组件样式方案

准备工作

首先创建一个react项目,执行npx create-react-app react-css

然后再创建一个components,文件夹,在本篇中以一个例子会在components下创建一个组件来进行演示。

第一种用法: 行内css

js 复制代码
export default function StyleCssComponent() {
  return (
    <button
      style={{
        outline: "none",
        border: "none",
        borderRadius: "5px",
        backgroundColor: "#409EFF",
        fontSize: "14px",
        color: "#fff",
        padding: "6px 12px",
      }}
    >
      按钮
    </button>
  );
}

行内css 书写注意点:

  1. 要写在一个对象里面
  2. 两个单词的属性需要采用驼峰写法

行内样式的优缺点:

优点: 可以动态计算,所以行内css 的使用场景一般是需要进行动态计算的时候才会用到,比如说动态获取窗口变化来计算当前盒子的宽高

缺点: 行内样式写多了会使代码的结构看上去非常乱,且不好维护,也不好重用

第二种写法: 普通css 文件导入

1. 静态类名写法

ClassCssComponent.css

css 复制代码
.btn-primary {
  outline: none;
  border: none;
  border-radius: 5px;
  background-color: #409EFF;
  font-size: 14px;
  color: #fff;
  padding: 6px 12px;
}

组件里面进行导入使用:

js 复制代码
import "../assets/css/ClassCssComponent.css";
export default function ClassCssComponent() {
  return <button className="btn-primary">按钮</button>;
}

采用css文件导入的写法的注意点: 标签上使用className 进行使用,而不是class

需要根据条件来写class 的写法,比如说button 按钮上默认有一个class 类名,另一个class 类名需要更根据条件进行添加怎么写呢?

2. 第一种动态类名写法

ClassCssComponent.css

css 复制代码
.btn {
  outline: none;
  border: 1px solid #ddd;
  border-radius: 5px;
  font-size: 14px;
  color: #ccc;
  padding: 6px 12px;
}
.btn-primary {
  background-color: #409EFF;
  color: #fff;
}

ClassCssComponent.js

js 复制代码
import "../assets/css/ClassCssComponent.css";
export default function ClassCssComponent() {
  const type = "primary";
  return <button className={"btn " + (type ? "btn-primary" : "")}>按钮</button>;
}

这种写法只有一种情况的判断的的时候看上去没太大问题,但是如果有多种情况,比如说还有btn-success, btn-info,btn-warning, btn-danger,那么这个三元表表达式就会变得很复杂,会使代码阅读变得非常困难。

3. 第二种动态类名写法

ClassCssComponent.css

css 复制代码
.btn {
  outline: none;
  border: 1px solid #ddd;
  border-radius: 5px;
  font-size: 14px;
  color: #333;
  padding: 6px 12px;
  background-color: #fff;
}
.btn-primary {
  background-color: #409EFF;
  color: #fff;
}
.btn-success {
  background-color: #67C23A;
  color: #fff;
}
.btn-info {
  background-color: #909399;
  color: #fff;
}
.btn-warning {
  background-color: #E6A23C;
  color: #fff;
}
.btn-danger {
  background-color: #409EFF;
  color: #F56C6C;
}
js 复制代码
import "../assets/css/ClassCssComponent.css";
export default function ClassCssComponent() {
  const type = "primary";
  let btnTypeClass = "";
  if (type === "primary") {
    btnTypeClass = "btn-primary";
  } else if (type === "success") {
    btnTypeClass = "btn-success";
  } else if (type === "info") {
    btnTypeClass = "btn-info";
  } else if (type === "warning") {
    btnTypeClass = "btn-warning";
  } else if ("danger") {
    btnTypeClass = "btn-danger";
  }
  return <button className={"btn " + btnTypeClass}>按钮</button>;
}

这种情况相对于第一种解决方案,在有多种条件来判断class类名的添加的时候,相对会好一些,但是这也不是太完美的一种写法。再想想有没有一种写法可想以和Vue 那样,写成一个对象,键名是class 类名称,值的真假来决定这个class 类名要不要显示呢?其实是有办法的,可以借助第三方库来实现。

4. 第三种动态类名写法(借助classNames)

安装 classnames

npm i classnames

使用:

js 复制代码
import "../assets/css/ClassCssComponent.css";
import classnames from "classnames";
export default function ClassCssComponent() {
  const type = "primary";
  const btnTypeClass = classnames("btn", {
    "btn-primary": type === "primary",
    "btn-success:": type === "success",
    "btn-info": type === "info",
    "btn-warning": type === "warning",
    "btn-danger": type === "danger",
  });
  return <button className={btnTypeClass}>按钮</button>;
}

这样同样能达到前面的效果,写法比之前好看多了。

classname 也支持数组形式的写法:

js 复制代码
import "../assets/css/ClassCssComponent.css";
import classnames from "classnames";
export default function ClassCssComponent() {
  const type = "primary";
  const btnTypeClass = classnames([
    "btn",
    {
      "btn-primary": type === "primary",
      "btn-success:": type === "success",
      "btn-info": type === "info",
      "btn-warning": type === "warning",
      "btn-danger": type === "danger",
    },
  ]);
  return <button className={btnTypeClass}>按钮</button>;
}

classnames还支持很多种写法,更多写法可以查看官方文档 github.com/JedWatson/c...

三、模块化css

到这里class 的写法已接近完美了,但其实还是存在一些问题,组件之间的样式会相互影响。

来看个案例,现在有两个组件,一个BoxComponent1.js,一个BoxComponent2.js,BoxComponent1.js导入一个BoxComponent1.css, 一个BoxComponent2.js导入BoxComponent2.css

BoxComponent1.js

js 复制代码
import "../assets/css/BoxComponent1.css";
export default function BoxComponent1() {
  return <div className="box">box1</div>;
}

BoxComponent1.css

css 复制代码
.box {
  width: 100px;
  height: 100px;
  background: #f00;
  color: #fff;
  font-size: 40px;
  margin: 20px;
  display: flex;
  justify-content: center;
  align-items: center;
}

BoxComponent2.js

js 复制代码
import "../assets/css/BoxComponent2.css";
export default function BoxComponent2() {
  return <div className="box">box2</div>;
}

BoxComponent2.css

css 复制代码
.box {
  width: 200px;
  height: 200px;
  background: greenyellow;
  color: #fff;
  font-size: 40px;
  margin: 20px;
  display: flex;
  justify-content: center;
  align-items: center;
}

按照我们的想法这两个样式应该是不一样的,box1是红色,box2是绿色,box1宽高是100px,box2宽高是200px。但是当你打开浏览器的时候你会惊奇的发现,两个样式显示居然是一样的,都采用了box2的样式。如下图:

这显然不是我们想要的效果。为什么会出现这种情况呢,因为 create-react-app 创建的项目是单页面应用,虽然我们把css 写在了不同的文件,但是打包之后css都会打包到一个文件里面。来执行下打包命令 npm run build 看下是不是这样的.

可以看到box1和box2的都合并到了一个里面。这就是造成样式互相影响的原因,在开发环境是直接将css 全部都放入到了页面的style中。

这样同样都会相互影响。那这个问题怎么解决呢?这个时候就需要用到css模块化了。npx create-react-app 创建的项目 已经自带css 模块化了,不需要再去安装依赖。来看下具体的使用。

  1. 首先需要将BoxComponent1.css改成 BoxComponent1.module.css
  2. 修改BoxComponent1.js中修改导入路径为: import box1Css from "../assets/css/BoxComponent1.module.css";
  3. 使用类名由 className="box"改为className={box1Css.box}

修改后的BoxComponent1.js如下

js 复制代码
import box2Css from "../assets/css/BoxComponent2.module.css";
export default function BoxComponent2() {
  return <div className={box2Css.box}>box2</div>;
}

BoxComponent2 的修改方式和BoxComponent1一样。

修改完成之后,查看效果:

可以看到,现在就使用了各自的样式了。css 模块化这怎么做到样式隔离的呢,css模块会在编译后会给我们的类名加一个前缀和后缀,前缀为组件名称,后缀是随机字符串。

这样我们就很好的解决了样式隔离问题。

今天就分享到这里了,感谢收看,本篇收录到React 知识储备专栏,欢迎关注后续更新

相关推荐
CF14年老兵2 分钟前
从JS到Python:一个前端开发者的丝滑转型之路
前端·后端·trae
庸懒4 分钟前
Electron自定义菜单栏及Mac最大化无效的问题解决
前端·macos·electron
I'mxx22 分钟前
【vue(一))路由】
前端·javascript·vue.js
CF14年老兵24 分钟前
构建闪电级i18n替代方案:我为何抛弃i18next选择原生JavaScript
前端·react.js·trae
布兰妮甜25 分钟前
Vite 为什么比 Webpack 快?原理深度分析
前端·webpack·node.js·vite
EndingCoder36 分钟前
Chrome插件开发实战:从零开发高效Chrome插件,提升浏览器生产力
前端·chrome
芝士加37 分钟前
从双端到一次搞定,一个老码农的真香体验
前端·开源
白云~️1 小时前
html img标签设置默认图片,防止图片路径不存在导致图片不展示影响页面美观
java·前端·html
xixixin_1 小时前
【HTML】在页面中画一条0.5px的线
前端·css·uni-app·html·css3