<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          如何優(yōu)雅地覆蓋組件庫(kù)樣式?

          共 4345字,需瀏覽 9分鐘

           ·

          2022-05-18 12:10

          組件庫(kù)的樣式覆蓋不掉,這應(yīng)該是很多前端在工作中遇到過(guò)的問(wèn)題。今天從實(shí)際案例出發(fā)分析原因,最后會(huì)給出在React和Vue項(xiàng)目中的最優(yōu)解。

          本文會(huì)講清:

          1. React中CSS Module的原理是什么?:global是做什么的?
          2. Vue中Scoped的原理是什么?深度作用選擇器是什么?

          先不講概念,直接從需求出發(fā):我使用了Antd組件庫(kù)來(lái)展示一個(gè)日歷。

          ad9758f2359c6167d0df13872557b934.webp現(xiàn)在我想將當(dāng)前日期上面的藍(lán)色邊框變成紫色。

          公眾號(hào)后臺(tái)回復(fù)「101」獲取React版本的在線地址,回復(fù)「102」獲取Vue版本的在線地址

          可以試試你能不能實(shí)現(xiàn)。

          不管是React還是Vue,整個(gè)Calendar是被封裝起來(lái)的,我們沒(méi)有辦法在組件外簡(jiǎn)單加上style/class改動(dòng)內(nèi)部的樣式。

          import?{?Calendar?}?from?'antd';
          ...
          "myWrapper">
          ??<Calendar?class="custom"/>
          </div>
          定位要覆蓋的樣式

          首先用開(kāi)發(fā)者工具定位對(duì)應(yīng)的樣式:.ant-picker-calendar-date-today,這就是我們要修改的地方。

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

          熟悉webpack的人應(yīng)該知道,引入的CSS文件最終都會(huì)被style-loader處理。簡(jiǎn)單來(lái)說(shuō),它的作用就是把CSS文件打包,放在style標(biāo)簽內(nèi),最后塞進(jìn)HTML中作為一個(gè)內(nèi)部樣式表。不管是組件庫(kù)的樣式還是我們寫(xiě)的自定義樣式都是這樣處理的。62aa413186f8a9e5efff5f9d9ce288b5.webp我們要把組件庫(kù)的樣式先于自定義樣式引入,這樣自定義樣式才能有更高的優(yōu)先級(jí)。

          修改源文件

          直接改組件庫(kù)的CSS源碼是最簡(jiǎn)單粗暴的方法。打開(kāi)你項(xiàng)目的node_modules文件夾,一層層點(diǎn)開(kāi),找到對(duì)應(yīng)樣式文件,按照需求修改即可。

          個(gè)人項(xiàng)目這樣處理確實(shí)可行,但是團(tuán)隊(duì)合作時(shí),同步別人本地的node_modules就比較麻煩,只能算一個(gè)60分解法。

          全局CSS文件

          之前提到,把自己寫(xiě)的的CSS文件放在組件庫(kù)的樣式后面,可以保障自定義有更高優(yōu)先級(jí)。只要重寫(xiě)同名的樣式,理論上就能實(shí)現(xiàn)覆蓋組了。

          但這樣??處理會(huì)發(fā)現(xiàn)并不起作用:

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

          //?組件庫(kù)的樣式
          import?'ant-design-vue/dist/antd.css';?
          //?自定義樣式
          import?'./demo.css'
          import?{?Calendar?}?from?'antd';
          ...
          "myWrapper">
          ??<Calendar?/>
          </div>
          ...

          因?yàn)檫@里還涉及CSS組合選擇器的優(yōu)先級(jí)。

          基礎(chǔ)的優(yōu)先級(jí)應(yīng)該不用贅述:!important>內(nèi)聯(lián)樣式>ID選擇器>類選擇器>標(biāo)簽選擇器。(!important這種hack會(huì)導(dǎo)致項(xiàng)目不好維護(hù),不提倡使用)

          在這個(gè)基礎(chǔ)上還有五種組合選擇器要對(duì)優(yōu)先級(jí)分?jǐn)?shù)做累計(jì),以類選擇器為例:

          1. 后代選擇器(空格):.A .B,選擇.A元素后的所有.B元素,
          2. 子元素選擇器(大于號(hào)):.A>.B,選擇.A元素的直接后代中的.B元素
          3. 相鄰兄弟選擇器(加號(hào)):.A+.B,選擇.A元素后緊鄰的第一個(gè)兄弟.B元素
          4. 后續(xù)兄弟選擇器(~號(hào)):.A~.B,選擇.A元素后所有的兄弟.B元素
          5. 交集選擇器(連在一起):.A.B選擇自身同時(shí)擁有.A和.B兩個(gè)屬性的元素

          上面幾個(gè)規(guī)則看著很復(fù)雜,其實(shí)用的多的就是第一個(gè)后代選擇器,記住它就行。Antd組件庫(kù)用的就是它:

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

          如果說(shuō)一個(gè)類選擇器優(yōu)先級(jí)分?jǐn)?shù)是10分,那三個(gè)形成的后代選擇器就是30分。

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

          .ant-picker-calendar-date-today?{
          ??border-color:?purple;?//?覆蓋為紫色
          }

          需要完整重寫(xiě)整個(gè)選擇器才能實(shí)現(xiàn)想要的效果。

          這里補(bǔ)充一點(diǎn),同樣也是組合選擇器,但并集選擇器(逗號(hào))優(yōu)先級(jí)不累計(jì):.A, .B,選擇.A或者.B元素(可以是逗號(hào)+空格)

          樣式隔離CSS Module和Scoped

          上面我們引入自定義的全局CSS文件,實(shí)現(xiàn)了樣式的覆蓋,但是這種解法只能給80分。因?yàn)樵趯?shí)際工作中,項(xiàng)目Owner通常不允許使用全局CSS,這會(huì)造成樣式污染:你定義了一個(gè)樣式my_button,團(tuán)隊(duì)其他人恰巧也命名為my_button,這就造成樣式?jīng)_突。

          我們需要給每個(gè)文件做樣式隔離,就好像是給它一個(gè)命名空間。通常使React項(xiàng)目使用的是用的是CSS Module,Vue項(xiàng)目使用Scoped標(biāo)記。

          接下來(lái)會(huì)講清兩種樣式隔離的原理,以及使用樣式隔離時(shí)怎么覆蓋組件庫(kù)的樣式。

          React的CSS Module

          首先來(lái)了解一下CSS Module的原理。它的使用很簡(jiǎn)單,在CSS文件加一個(gè)后綴.module,然后當(dāng)做一個(gè)變量引入到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屬性都會(huì)加上一個(gè)哈希值作為命名空間。

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

          可以看到,原本的CSS選擇器和HTML元素類名都從myWrapper變成了demo_myWrapper__Hd9Qg,前面加上了文件名,后面加上了哈希值,這樣就能保障樣式只在當(dāng)前這個(gè)文件下生效了。

          但是在這種樣式隔離情況下,我們?cè)居米鞲采w的CSS也被加上了哈希值,就像下圖這樣,這時(shí)沒(méi)有辦法選中UI組件,覆蓋也就不會(huì)成功。230057c6b9ca3548ab727b1187baef5e.webp

          所以,React給我們提供了一個(gè)語(yǔ)法:global。它生效范圍內(nèi)的樣式會(huì)被當(dāng)作全局CSS。

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

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

          SCSS或SASS中,還可以使用嵌套語(yǔ)法:

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

          最后編譯出來(lái)的代碼如下:

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

          4afbd5f0e7a4ad51731be43809e4da9d.webp借助:global語(yǔ)法,即使使用CSS Module進(jìn)行樣式隔離也可以如愿實(shí)現(xiàn)覆蓋功能。

          Vue中的Scoped

          Vue中也有類似的樣式隔離功能,使用Scoped標(biāo)記CSS部分,使用也很簡(jiǎn)單??:

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

          編譯出來(lái)的代碼如下??:

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

          可以看到,它的原理和CSS Module不太一樣,Vue的Scoped會(huì)使CSS選擇器后加上一個(gè)中括號(hào)。

          這并不是Vue獨(dú)創(chuàng)的語(yǔ)法,而是屬性選擇器。.myWrapper[data-v-2fc5154c]代表選擇擁有data-v-2fc5154c這個(gè)屬性的、同時(shí)是myButton類的HTML元素。只有這個(gè)文件內(nèi)部的HTML元素才會(huì)被打上data-v-2fc5154c這個(gè)屬性。其余文件的HTML元素即使是myWrapper類,這個(gè)樣式也不會(huì)對(duì)他生效。

          回到相同的問(wèn)題,假如Vue項(xiàng)目在使用了Scoped做樣式隔離,我們用于覆蓋的樣式也會(huì)加上屬性選擇器,但是UI組件內(nèi)部的HTML元素都沒(méi)有該屬性??。1f3bffe061c45752eafdcb16f2d6d882.webp

          所以Vue提供了一個(gè)類似的語(yǔ)法:深度作用選擇器。

          使用很簡(jiǎn)單,把要“滲透“進(jìn)組件內(nèi)部的樣式前面加上>>>,作用域內(nèi)的CSS樣式都不會(huì)帶上哈希值作為屬性選擇器。

          <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
          /*?作用域內(nèi)的CSS都沒(méi)有帶上屬性選擇器?*/
          .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>

          d03820693bcbc327b9e73db121bebdd7.webp

          借助深度作用選擇器,可以將要用于覆蓋CSS“滲透”進(jìn)組件內(nèi)部。

          也可以將>>>寫(xiě)成/deep/或者::v-deep

          相較于React的:global,Vue的深度作用選擇器是一種更優(yōu)秀的方案,它必須要一個(gè)前導(dǎo)(也就是上面例子中的.myWrapper選擇器),前導(dǎo)依舊會(huì)被打上哈希值作為屬性選擇器,要滲透進(jìn)去的樣式實(shí)際上是作為它的子選擇器,只在當(dāng)前這個(gè)文件下生效,徹底避免造成全局污染。

          結(jié)語(yǔ)

          本文通過(guò)如何修改UI組件內(nèi)部樣式為切入點(diǎn),分析了幾種解法。了解了組合選擇器的優(yōu)先級(jí)分?jǐn)?shù)累加,以及在實(shí)際React、Vue項(xiàng)目用到的樣式隔離方案——CSS Module和Scoped的原理,最后是介紹了在樣式隔離的情況下,如何使用:global和深度作用選擇器做樣式覆蓋。

          如果這篇文章對(duì)你有幫助,給我點(diǎn)個(gè)贊和在看吧~

          你的鼓勵(lì)是我創(chuàng)作的最大動(dòng)力??

          瀏覽 78
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美日韩国产中文 | 国产免费操逼视频 | 97免费福利视频 | 欧美日韩免费在线视频 | 四虎最新域名 |