您好,登錄后才能下訂單哦!
本篇內容主要講解“React和Vue項目問題怎么解決”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“React和Vue項目問題怎么解決”吧!
組件庫的樣式覆蓋不掉,這應該是很多前端在工作中遇到過的問題。今天從實際案例出發分析原因,最后會給出在React和Vue項目中的最優解。
本文會講清:
React中CSS Module的原理是什么?:global
是做什么的?
Vue中Scoped的原理是什么?深度作用選擇器是什么?
先不講概念,直接從需求出發:我使用了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; // 覆蓋為紫色 }
需要完整重寫整個選擇器才能實現想要的效果。
這里補充一點,同樣也是組合選擇器,但并集選擇器(逗號)優先級不累計:
.A, .B
選擇.A或者.B元素(可以是逗號+空格)
上面我們引入自定義的全局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選擇器),前導依舊會被打上哈希值作為屬性選擇器,要滲透進去的樣式實際上是作為它的子選擇器,只在當前這個文件下生效,徹底避免造成全局污染。
到此,相信大家對“React和Vue項目問題怎么解決”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。