>  기사  >  웹 프론트엔드  >  구성 요소 라이브러리 스타일을 재정의하는 방법은 무엇입니까? React 및 Vue 프로젝트 솔루션에 대한 간략한 분석

구성 요소 라이브러리 스타일을 재정의하는 방법은 무엇입니까? React 및 Vue 프로젝트 솔루션에 대한 간략한 분석

青灯夜游
青灯夜游앞으로
2022-05-16 11:15:524246검색

구성 요소 라이브러리 스타일을 재정의하는 방법은 무엇입니까? 다음 기사에서는 ReactVue 프로젝트에서 구성 요소 라이브러리 스타일을 우아하게 재정의하는 방법을 소개합니다. 도움이 되길 바랍니다.

구성 요소 라이브러리 스타일을 재정의하는 방법은 무엇입니까? React 및 Vue 프로젝트 솔루션에 대한 간략한 분석

구성 요소 라이브러리의 스타일은 덮어쓸 수 없습니다. 이는 많은 프런트 엔드가 작업에서 직면했던 문제입니다. 오늘은 실제 사례를 바탕으로 이유를 분석하고 최종적으로 React 및 Vue 프로젝트에서 최적의 솔루션을 제공하겠습니다.

이 기사에서는 명확하게 설명합니다.

  • React에서 CSS 모듈의 원리는 무엇입니까? :global은 무엇을 합니까? :global是做什么的?

  • Vue中Scoped的原理是什么?深度作用选择器是什么?(学习视频分享:vue视频教程

先不讲概念,直接从需求出发:我使用了Antd组件库来展示一个日历。

구성 요소 라이브러리 스타일을 재정의하는 방법은 무엇입니까? React 및 Vue 프로젝트 솔루션에 대한 간략한 분석

现在我想将当前日期上面的蓝色边框变成紫色。

可以试试你能不能实现。

不管是React还是Vue,整个Calendar是被封装起来的,我们没有办法在组件外简单加上style/class改动内部的样式。

import { Calendar } from 'antd';
...
<div className="myWrapper">
  <Calendar class="custom"/>
</div>

定位要覆盖的样式


首先用开发者工具定位对应的样式:.ant-picker-calendar-date-today,这就是我们要修改的地方。

구성 요소 라이브러리 스타일을 재정의하는 방법은 무엇입니까? React 및 Vue 프로젝트 솔루션에 대한 간략한 분석

.ant-picker-calendar-full .ant-picker-panel .ant-picker-calendar-date-today {
    border-color: #1890ff; 
}

熟悉webpack的人应该知道,引入的CSS文件最终都会被style-loader处理。简单来说,它的作用就是把CSS文件打包,放在style标签内,最后塞进HTML中作为一个内部样式表。不管是组件库的样式还是我们写的自定义样式都是这样处理的。

구성 요소 라이브러리 스타일을 재정의하는 방법은 무엇입니까? React 및 Vue 프로젝트 솔루션에 대한 간략한 분석

我们要把组件库的样式先于自定义样式引入,这样自定义样式才能有更高的优先级。

修改源文件


直接改组件库的CSS源码是最简单粗暴的方法。打开你项目的node_modules文件夹,一层层点开,找到对应样式文件,按照需求修改即可。

个人项目这样处理确实可行,但是团队合作时,同步别人本地的node_modules就比较麻烦,只能算一个60分解法。

全局CSS文件


之前提到,把自己写的的CSS文件放在组件库的样式后面,可以保障自定义有更高优先级。只要重写同名的样式,理论上就能实现覆盖组了。

但这样?处理会发现并不起作用:

/* src/demo.css */
.ant-picker-calendar-date-today {
  border-color: purple; /* 覆盖为紫色 */
}
// src/Demo.js

// 组件库的样式
import &#39;ant-design-vue/dist/antd.css&#39;; 
// 自定义样式
import &#39;./demo.css&#39;
import { Calendar } from &#39;antd&#39;;
...
<div className="myWrapper">
  <Calendar />
</div>
...

因为这里还涉及CSS组合选择器的优先级。

基础的优先级应该不用赘述:!important>内联样式>ID选择器>类选择器>标签选择器。(!important这种hack会导致项目不好维护,不提倡使用)

在这个基础上还有五种组合选择器要对优先级分数做累计,以类选择器为例:

  • 后代选择器(空格):.A .B选择.A元素后的所有.B元素,

  • 子元素选择器(大于号):.A>.B选择.A元素的直接后代中的.B元素

  • 相邻兄弟选择器(加号):.A+.B选择.A元素后紧邻的第一个兄弟.B元素

  • 后续兄弟选择器(~号):.A~.B选择.A元素后所有的兄弟.B元素

  • 交集选择器(连在一起):.A.B选择自身同时拥有.A和.B两个属性的元素

上面几个规则看着很复杂,其实用的多的就是第一个后代选择器,记住它就行。Antd组件库用的就是它:

.ant-picker-calendar-full .ant-picker-panel .ant-picker-calendar-date-today {
    border-color: #1890ff; 
}

如果说一个类选择器优先级分数是10分,那三个形成的后代选择器就是30分。

而自定义的样式?只有10分,所以即使放在更后面引入,也不能成功覆盖。

.ant-picker-calendar-date-today {
  border-color: purple; // 覆盖为紫色
}

需要完整重写整个选择器才能实现想要的效果。

这里补充一点,同样也是组合选择器,但并集选择器(逗号)优先级不累计:.A, .B

🎜Vue에서 Scoped의 원리는 무엇인가요? 깊이 작업 선택기란 무엇입니까? (학습 영상 공유: vue 영상 튜토리얼🎜)🎜🎜 먼저 개념에 대해 이야기하지 말고 요구 사항부터 직접 시작하겠습니다. Antd 구성 요소 라이브러리를 사용하여 달력을 표시했습니다. 🎜🎜구성 요소 라이브러리 스타일을 재정의하는 방법은 무엇입니까? React 및 Vue 프로젝트 솔루션에 대한 간략한 분석🎜🎜지금 현재 날짜 위의 파란색 테두리를 보라색으로 변경하고 싶습니다. 🎜🎜당신이 그것을 달성할 수 있는지 확인해 볼 수 있습니다. 🎜🎜React이든 Vue이든 전체 Calendar는 캡슐화됩니다. 내부 스타일을 변경하기 위해 단순히 구성 요소 외부에 스타일/클래스를 추가할 수는 없습니다. 🎜
// src/Demo.js
import styles from &#39;./demo.module.css&#39;;
export default function Demo() {
  return (
    <div className={styles.myWrapper}>
      <Calendar />
    </div>
  );
}

덮어쓸 스타일 찾기


🎜먼저 개발자 도구를 사용하여 해당 스타일을 찾으세요: .ant-picker-calendar-date- 오늘, 이것이 우리가 수정하고 싶은 것입니다. <br>🎜🎜<img src="https://img.php.cn/upload/image/101/753/234/1652670415522180.png" title="1652670415522180.png" alt="구성 요소 라이브러리 스타일을 재정의하는 방법은 무엇입니까? React 및 Vue 프로젝트 솔루션에 대한 간략한 분석">🎜<pre class="brush:js;toolbar:false;">/* src/demo.module.css */ .myWrapper { border: 5px solid black; }</pre>🎜webpack에 익숙한 사람들은 가져온 CSS 파일이 결국 스타일 로더에 의해 처리된다는 점을 알아야 합니다. 간단히 말해서, 그 기능은 CSS 파일을 패키징하여 스타일 태그에 배치하고 마지막으로 내부 스타일 시트로 HTML에 삽입하는 것입니다. 이는 구성 요소 라이브러리의 스타일이든 우리가 작성한 사용자 정의 스타일이든 상관없이 수행됩니다. 🎜🎜<img src="https://img.php.cn/upload/image/480/863/763/1652670424615390.png" title="1652670424615390.png" alt="구성 요소 라이브러리 스타일을 재정의하는 방법은 무엇입니까? React 및 Vue 프로젝트 솔루션에 대한 간략한 분석">🎜🎜us 구성 요소 라이브러리의 스타일은 사용자 정의 스타일보다 먼저 도입되어야 사용자 정의 스타일이 더 높은 우선순위를 가질 수 있습니다. 🎜<h2><strong>소스 파일 수정</strong></h2> <hr>🎜 구성 요소 라이브러리의 CSS 소스 코드를 직접 변경하는 것이 가장 간단하고 조악한 방법입니다. 프로젝트의 node_modules 폴더를 열고 레이어별로 클릭한 후 해당 스타일 파일을 찾아 필요에 따라 수정하세요. <br>🎜🎜개인 프로젝트를 이런 방식으로 처리하는 것은 실제로 가능하지만, 팀으로 작업할 때는 다른 사람의 로컬 node_modules를 동기화하는 것이 더 번거롭고 60 분해 방법이라고밖에 볼 수 없습니다. 🎜<h2><strong>전역 CSS 파일</strong></h2> <hr>🎜앞서 언급했듯이 구성요소 라이브러리의 스타일 뒤에 자체 CSS 파일을 배치하면 사용자 정의의 우선순위가 더 높아질 수 있습니다. 동일한 이름으로 스타일을 다시 작성하기만 하면 이론적으로 재정의 그룹을 구현할 수 있습니다. <br>🎜🎜하지만 처리 과정에서 작동하지 않는 것으로 확인됩니다. 🎜<pre class="brush:js;toolbar:false;">&lt;style&gt; .demo_myWrapper__Hd9Qg { border: 5px solid black; } &lt;/style&gt; &lt;div class=&quot;demo_myWrapper__Hd9Qg&quot;&gt; ... &lt;/div&gt;</pre><pre class="brush:js;toolbar:false;">:global(.ant-picker-calendar-full .ant-picker-panel .ant-picker-calendar-date-today) { border-color:purple; /* 覆盖为紫色 */ }</pre>🎜CSS 조합 선택기의 우선순위도 관련되어 있기 때문입니다. 🎜🎜기본 우선순위는 말할 필요도 없이 <code>!important>Inline Styles>ID Selector>Class Selector>Tag Selector입니다. (!important 이러한 종류의 해킹은 프로젝트 유지를 어렵게 하며 사용을 권장하지 않습니다.) 🎜🎜이를 바탕으로 우선 순위 점수를 축적해야 하는 조합 선택기가 5개 있습니다. 클래스 선택기를 예로 들어 보겠습니다. 🎜🎜🎜 🎜하위 항목 선택기(공백): .A .B .A 요소 뒤의 모든 .B 요소를 선택합니다. 🎜🎜🎜하위 요소 선택기(보다 큼 기호): . A> .B.A 요소의 직계 자손 중에서 .B 요소를 선택합니다🎜🎜🎜인접 형제 선택기(더하기 기호): .A+.B.A 요소를 선택합니다. 🎜🎜🎜 바로 뒤의 첫 번째 sibling.B 요소 후속 형제 선택기(~ 번호): .A~.B는 A 요소🎜 뒤의 모든 sibling.B 요소를 선택합니다. 🎜 🎜교집합 선택기(함께 연결됨): .A.B는 .A 및 .B 속성을 모두 갖는 요소를 선택합니다🎜🎜위의 규칙은 복잡해 보일 수 있지만 가장 실용적입니다. 하나는 첫 번째 자손 선택자라는 점만 기억하세요. Antd 구성 요소 라이브러리에서는 다음과 같이 사용합니다. 🎜
:global {
  .ant-picker-calendar-full .ant-picker-panel .ant-picker-calendar-date-today {
    border-color:purple;
  }
}
🎜클래스 선택기의 우선 순위 점수가 10점인 경우 형성된 세 개의 하위 선택기의 우선 순위 점수는 30점입니다. 🎜🎜그리고 커스텀 스타일은 10포인트만 있어서 나중에 소개한다고 해도 성공적으로 커버가 안 되더라구요. 🎜
/* 加上了哈希*/
.demo_myWrapper__Hd9Qg {
  border: 5px solid black;
}
/* :global作用域下都不会加上哈希*/
.ant-picker-calendar-full .ant-picker-panel .ant-picker-calendar-date-today {
  border-color:purple;
}
🎜원하는 효과를 얻으려면 전체 선택기를 완전히 다시 작성해야 합니다. 🎜
🎜 여기에 추가할 점은 조합 선택자이기도 하지만 조합 선택자(쉼표)의 우선순위는 누적되지 않는다는 점입니다. .A, .B는 .A 또는 . B 요소(쉼표 + 공백 가능)🎜

样式隔离CSS Module和Scoped


上面我们引入自定义的全局CSS文件,实现了样式的覆盖,但是这种解法只能给80分。因为在实际工作中,项目Owner通常不允许使用全局CSS,这会造成样式污染:你定义了一个样式my_button,团队其他人恰巧也命名为my_button,这就造成样式冲突。

我们需要给每个文件做样式隔离,就好像是给它一个命名空间。通常使React项目使用的是用的是CSS Module,Vue项目使用Scoped标记。

接下来会讲清两种样式隔离的原理,以及使用样式隔离时怎么覆盖组件库的样式。

React的CSS Module

首先来了解一下CSS Module的原理。它的使用很简单,在CSS文件加一个后缀.module,然后当做一个变量引入到JS文件中。

// src/Demo.js
import styles from &#39;./demo.module.css&#39;;
export default function Demo() {
  return (
    <div className={styles.myWrapper}>
      <Calendar />
    </div>
  );
}
/* src/demo.module.css */
.myWrapper {
  border: 5px solid black;
}

被编译后?,插入的样式表和元素的class属性都会加上一个哈希值作为命名空间。

<style>
.demo_myWrapper__Hd9Qg {
  border: 5px solid black;
}
</style>
<div class="demo_myWrapper__Hd9Qg">
...
</div>

可以看到,原本的CSS选择器和HTML元素类名都从myWrapper变成了demo_myWrapper__Hd9Qg,前面加上了文件名,后面加上了哈希值,这样就能保障样式只在当前这个文件下生效了。

但是在这种样式隔离情况下,我们原本用作覆盖的CSS也被加上了哈希值,就像下图这样,这时没有办法选中UI组件,覆盖也就不会成功。

구성 요소 라이브러리 스타일을 재정의하는 방법은 무엇입니까? React 및 Vue 프로젝트 솔루션에 대한 간략한 분석

所以,React给我们提供了一个语法:global。它生效范围内的样式会被当作全局CSS。

具体使用如下,在CSS文件中,使用:global包裹希望全局生效的样式

:global(.ant-picker-calendar-full .ant-picker-panel .ant-picker-calendar-date-today) {
  border-color:purple; /* 覆盖为紫色 */
}

SCSS或SASS中,还可以使用嵌套语法:

:global {
  .ant-picker-calendar-full .ant-picker-panel .ant-picker-calendar-date-today {
    border-color:purple;
  }
}

最后编译出来的代码如下:

/* 加上了哈希*/
.demo_myWrapper__Hd9Qg {
  border: 5px solid black;
}
/* :global作用域下都不会加上哈希*/
.ant-picker-calendar-full .ant-picker-panel .ant-picker-calendar-date-today {
  border-color:purple;
}

구성 요소 라이브러리 스타일을 재정의하는 방법은 무엇입니까? React 및 Vue 프로젝트 솔루션에 대한 간략한 분석

借助:global语法,即使使用CSS Module进行样式隔离也可以如愿实现覆盖功能。

Vue中的Scoped

Vue中也有类似的样式隔离功能,使用Scoped标记CSS部分,使用也很简单?:

<style scoped>
.myWrapper{
  border: 5px solid black
}
</style>
...
<div class="myWrapper" >
  <Calendar />
</div>
...

编译出来的代码如下:

<style>
.myWrapper[data-v-2fc5154c] {
  border: 5px solid black
}
</style>
<div class="myWrapper" data-v-2fc5154c>
  ...
</div>

可以看到,它的原理和CSS Module不太一样,Vue的Scoped会使CSS选择器后加上一个中括号。

这并不是Vue独创的语法,而是属性选择器。.myWrapper[data-v-2fc5154c]代表选择拥有data-v-2fc5154c这个属性的、同时是myButton类的HTML元素。只有这个文件内部的HTML元素才会被打上data-v-2fc5154c这个属性。其余文件的HTML元素即使是myWrapper类,这个样式也不会对他生效。

回到相同的问题,假如Vue项目在使用了Scoped做样式隔离,我们用于覆盖的样式也会加上属性选择器,但是UI组件内部的HTML元素都没有该属性。

구성 요소 라이브러리 스타일을 재정의하는 방법은 무엇입니까? React 및 Vue 프로젝트 솔루션에 대한 간략한 분석

所以Vue提供了一个类似的语法:深度作用选择器。

使用很简单,把要“渗透“进组件内部的样式前面加上,作用域内的CSS样式都不会带上哈希值作为属性选择器。

<style scoped>
.myWrapper>>>
.ant-picker-calendar-full 
.ant-picker-panel 
.ant-picker-calendar-date-today{
  border-color:purple
}
</style>
<template>
  <div class="myWrapper" >
    <Calendar  />
  </div>
</template>

编译后

<style>
.myWrapper[data-v-2fc5154c]
.ant-picker-calendar-full
.ant-picker-panel
/* 作用域内的CSS都没有带上属性选择器 */
.ant-picker-calendar-date-today {
  border-color:purple
}
</style>

<div class="myWrapper" data-v-2fc5154c>
  <div class="ant-picker-calendar-full" data-v-2fc5154c>
    <div class="ant-picker-date-panel">
      <td class="ant-picker-cell-today"></td>
    </div>
  </div>
</div>

구성 요소 라이브러리 스타일을 재정의하는 방법은 무엇입니까? React 및 Vue 프로젝트 솔루션에 대한 간략한 분석

借助深度作用选择器,可以将要用于覆盖CSS“渗透”进组件内部。

也可以将写成/deep/或者::v-deep

相较于React的:global,Vue的深度作用选择器是一种更优秀的方案,它必须要一个前导(也就是上面例子中的.myWrapper选择器),前导依旧会被打上哈希值作为属性选择器,要渗透进去的样式实际上是作为它的子选择器,只在当前这个文件下生效,彻底避免造成全局污染。

结语

本文通过如何修改UI组件内部样式为切入点,分析了几种解法。了解了组合选择器的优先级分数累加,以及在实际React、Vue项目用到的样式隔离方案——CSS Module和Scoped的原理,最后是介绍了在样式隔离的情况下,如何使用:global和深度作用选择器做样式覆盖。

如果这篇文章对你有帮助,给我点个赞和在看吧~

(学习视频分享:web前端开发编程基础视频

위 내용은 구성 요소 라이브러리 스타일을 재정의하는 방법은 무엇입니까? React 및 Vue 프로젝트 솔루션에 대한 간략한 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 juejin.cn에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제