구성 요소 라이브러리 스타일을 재정의하는 방법은 무엇입니까? 다음 기사에서는 React 및 Vue 프로젝트에서 구성 요소 라이브러리 스타일을 우아하게 재정의하는 방법을 소개합니다. 도움이 되길 바랍니다.
구성 요소 라이브러리의 스타일은 덮어쓸 수 없습니다. 이는 많은 프런트 엔드가 작업에서 직면했던 문제입니다. 오늘은 실제 사례를 바탕으로 이유를 분석하고 최종적으로 React 및 Vue 프로젝트에서 최적의 솔루션을 제공하겠습니다.
이 기사에서는 명확하게 설명합니다.
React에서 CSS 모듈의 원리는 무엇입니까? :global
은 무엇을 합니까? :global
是做什么的?
Vue中Scoped的原理是什么?深度作用选择器是什么?(学习视频分享:vue视频教程)
先不讲概念,直接从需求出发:我使用了Antd组件库来展示一个日历。
现在我想将当前日期上面的蓝色边框变成紫色。
可以试试你能不能实现。
不管是React还是Vue,整个Calendar是被封装起来的,我们没有办法在组件外简单加上style/class改动内部的样式。
import { Calendar } from 'antd'; ... <div className="myWrapper"> <Calendar class="custom"/> </div>
首先用开发者工具定位对应的样式:.ant-picker-calendar-date-today
,这就是我们要修改的地方。
.ant-picker-calendar-full .ant-picker-panel .ant-picker-calendar-date-today { border-color: #1890ff; }
熟悉webpack的人应该知道,引入的CSS文件最终都会被style-loader处理。简单来说,它的作用就是把CSS文件打包,放在style标签内,最后塞进HTML中作为一个内部样式表。不管是组件库的样式还是我们写的自定义样式都是这样处理的。
我们要把组件库的样式先于自定义样式引入,这样自定义样式才能有更高的优先级。
直接改组件库的CSS源码是最简单粗暴的方法。打开你项目的node_modules文件夹,一层层点开,找到对应样式文件,按照需求修改即可。
个人项目这样处理确实可行,但是团队合作时,同步别人本地的node_modules就比较麻烦,只能算一个60分解法。
之前提到,把自己写的的CSS文件放在组件库的样式后面,可以保障自定义有更高优先级。只要重写同名的样式,理论上就能实现覆盖组了。
但这样?处理会发现并不起作用:
/* src/demo.css */ .ant-picker-calendar-date-today { border-color: purple; /* 覆盖为紫色 */ }
// src/Demo.js // 组件库的样式 import 'ant-design-vue/dist/antd.css'; // 自定义样式 import './demo.css' import { Calendar } from 'antd'; ... <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; // 覆盖为紫色 }
需要完整重写整个选择器才能实现想要的效果。
这里补充一点,同样也是组合选择器,但并集选择器(逗号)优先级不累计:
🎜Vue에서 Scoped의 원리는 무엇인가요? 깊이 작업 선택기란 무엇입니까? (학습 영상 공유: vue 영상 튜토리얼🎜)🎜🎜 먼저 개념에 대해 이야기하지 말고 요구 사항부터 직접 시작하겠습니다. Antd 구성 요소 라이브러리를 사용하여 달력을 표시했습니다. 🎜🎜🎜🎜지금 현재 날짜 위의 파란색 테두리를 보라색으로 변경하고 싶습니다. 🎜🎜당신이 그것을 달성할 수 있는지 확인해 볼 수 있습니다. 🎜🎜React이든 Vue이든 전체 Calendar는 캡슐화됩니다. 내부 스타일을 변경하기 위해 단순히 구성 요소 외부에 스타일/클래스를 추가할 수는 없습니다. 🎜.A, .B
// src/Demo.js import styles from './demo.module.css'; 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;"><style> .demo_myWrapper__Hd9Qg { border: 5px solid black; } </style> <div class="demo_myWrapper__Hd9Qg"> ... </div></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 './demo.module.css'; 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给我们提供了一个语法
: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; }借助
: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元素都没有该属性。
所以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>借助深度作用选择器,可以将要用于覆盖CSS“渗透”进组件内部。
也可以将
写成
/deep/
或者::v-deep
。相较于React的
:global
,Vue的深度作用选择器是一种更优秀的方案,它必须要一个前导(也就是上面例子中的.myWrapper选择器),前导依旧会被打上哈希值作为属性选择器,要渗透进去的样式实际上是作为它的子选择器,只在当前这个文件下生效,彻底避免造成全局污染。结语
本文通过如何修改UI组件内部样式为切入点,分析了几种解法。了解了组合选择器的优先级分数累加,以及在实际React、Vue项目用到的样式隔离方案——CSS Module和Scoped的原理,最后是介绍了在样式隔离的情况下,如何使用:global和深度作用选择器做样式覆盖。
如果这篇文章对你有帮助,给我点个赞和在看吧~
위 내용은 구성 요소 라이브러리 스타일을 재정의하는 방법은 무엇입니까? React 및 Vue 프로젝트 솔루션에 대한 간략한 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!