Vue項(xiàng)目中CSS?Modules和Scoped?CSS的介紹與區(qū)別
背景
在前端工程化飛速發(fā)展的時(shí)候,作為非編程語(yǔ)言的CSS在融入模塊化的浪潮時(shí)產(chǎn)生了很多問(wèn)題:
- 無(wú)法做到樣式模塊化
組件化開發(fā)是前端模塊化的核心,但是原生CSS的思想是樣式的層疊,對(duì)于組件來(lái)說(shuō)并不友好,會(huì)造成組件樣式被覆蓋等問(wèn)題。
于是我們希望樣式是存在作用域的,即在組件的作用域內(nèi),組件樣式只對(duì)該組件生效。
- 命名混亂
在大型項(xiàng)目中,多人合作經(jīng)常容易產(chǎn)生命名混亂的問(wèn)題,直接后果就是代碼風(fēng)格不統(tǒng)一、樣式?jīng)_突等。
- 高重復(fù)
組件開發(fā)也意味著有很多樣式代碼是重復(fù)的,在項(xiàng)目中顯得十分冗余。
于是我們希望存在一種機(jī)制可以導(dǎo)入和導(dǎo)出CSS,做到樣式的復(fù)用。
解決CSS模塊化的方案有很多種,在Vue項(xiàng)目中,Vue Loader支持的兩種分別是Scoped CSS和CSS Modules。
Scoped CSS是Vue Loader默認(rèn)支持的,因此在Vue項(xiàng)目中可以直接使用;
CSS Modules被Vue Loader視為模擬Scoped CSS的替代方案,也提供了集成來(lái)支持,但是需要寫入一些配置。
// vue.config.js // 使用vue-cli的話,可以直接在該文件中配置,不用暴露webpack的配置 ? module.exports = { css: { // 開啟CSS Modules requireModuleExtension: true; loaderOptions: { // 向loader傳遞配置選項(xiàng) css: { modules: { // 自定義類命名規(guī)則 // 在我們的項(xiàng)目中,對(duì)類的命名是根據(jù)環(huán)境不同而改變的,開發(fā)環(huán)境中會(huì)展示該類的文件路徑方便調(diào)試,其他環(huán)境中會(huì) 使用hash值封裝 localIdentName: process.env.NODE_ENV === 'development' ? '[path][name]__[local]' : '[hash:base62:8]', } } } } }
需要知道的是,這兩個(gè)解決方案都不是CSS的官方規(guī)范,只是我們通過(guò)一些構(gòu)建工具,比如Webpack或者腳手架來(lái)加載對(duì)應(yīng)的Loader,從而對(duì)CSS代碼進(jìn)行一些轉(zhuǎn)換,來(lái)做到實(shí)現(xiàn)模塊化的效果。
CSS Modules
原理
CSS Modules實(shí)現(xiàn)CSS模塊化的原理就是根據(jù)我們?cè)赾onfig文件中定義的類名命名規(guī)則給類生成一個(gè)獨(dú)一無(wú)二的命名,從而實(shí)現(xiàn)作用域的隔離。
- 轉(zhuǎn)化前
<style module> .example { color: red; } </style> ? <template> <div class="example">hi</div> </template>
- 轉(zhuǎn)化后
<!-- 轉(zhuǎn)化規(guī)則是自己定義的 --> <!-- 生產(chǎn)環(huán)境中,直接用hash值封裝 --> <style module> ._1TdbN_VT { color: red; } </style> ? <template> <div class="._1TdbN_VT">hi</div> </template> ? <!-- 開發(fā)環(huán)境中,會(huì)顯示來(lái)源 --> <style module> .src-views-login-Index__example { color: red; } </style> ? <template> <div class=".src-views-login-Index__example">hi</div> </template>
規(guī)則
- Vue項(xiàng)目中的使用
在style標(biāo)簽中需要聲明module特性:
<style module> ... </style>
聲明module特性后,Vue Loader會(huì)生成一個(gè)$style計(jì)算屬性,向組件注入CSS Modules對(duì)象,我們可以通過(guò)使用該計(jì)算屬性在template和JS中訪問(wèn)到CSS Modules對(duì)象。
<template> <!-- 直接通過(guò)$style來(lái)訪問(wèn)red類,同理$style作為計(jì)算屬性也支持對(duì)象和數(shù)組語(yǔ)法 --> <p :class="$style.red"> This should be red </p> </template>
- Composition:樣式的組合
.classA { color: green; background: red; } ? .classB { composes: classA; color: red; }
使用composes規(guī)則可以把其他類和該類的樣式組合起來(lái)
要注意composes聲明的規(guī)則必須在自身規(guī)則之前;
可以一次性組合多個(gè)class,類名之間用空格隔開,但是這些class都必須是local scoped的
- Dependencies:通過(guò)導(dǎo)入實(shí)現(xiàn)依賴
如果需要組合其他module里的樣式,可以通過(guò)導(dǎo)入的方式:
.classC { composes: classA from './style.css' }
- 要注意當(dāng)組合了不同CSS文件中的不同類時(shí),CSS Modules是默認(rèn)這些類之間不存在先后順序的,因此導(dǎo)入時(shí)要保證這些類之間沒(méi)有規(guī)則沖突
- 組合的類之間不能存在循環(huán)依賴
- composes實(shí)現(xiàn)的原理就是通過(guò)loader把import的CSS文件處理成ICSS格式的中間件,導(dǎo)出一個(gè)保存了所有l(wèi)ocal類名到global類名映射的對(duì)象,實(shí)際上這也是在JS文件中直接import CSS文件的原理
:global選擇器
:global()允許括號(hào)中聲明的選擇器命中全局,即其類名不會(huì)經(jīng)過(guò)規(guī)則封裝,因此不受作用域的限制。
實(shí)際項(xiàng)目中,當(dāng)我們希望修改所使用組件庫(kù)的默認(rèn)樣式時(shí),在使用CSS Modules方案的情況下,就可以通過(guò):global()來(lái)修改其默認(rèn)樣式,但是要注意最好外面有一層類封裝,否則可能影響全局樣式。
Vue3新特性
- 自定義module命名
<style module="login"> ... </style>
支持給module命名,可以用module名替代$style,比如<div :class="login.red"></div>。
- 組合式API中的CSS Modules
在setup()中可以使用useCssModuleAPI來(lái)獲取module對(duì)象。
- 在CSS中使用v-bind
支持在style中把某條rule的值和data中的一個(gè)數(shù)據(jù)綁定,比如:
.red { color: v-bind(color); }
Scoped CSS
原理
Vue Loader默認(rèn)使用CSS后處理器PostCSS來(lái)實(shí)現(xiàn)Scoped CSS,原理就是給聲明了scoped的樣式中選擇器命中的元素添加一個(gè)自定義屬性,再通過(guò)屬性選擇器實(shí)現(xiàn)作用域隔離樣式的效果。
- 轉(zhuǎn)化前
<style module> .example { color: red; } </style> ? <template> <div class="example">hi</div> </template>
- 轉(zhuǎn)化后
<!-- 用自定義屬性把類名封裝起來(lái)了 --> <style> .example[data-v-f3f3eg9] { color: red; } </style> ? <template> <div class="example" data-v-f3f3eg9>hi</div> </template>
規(guī)則
- 一個(gè)Vue文件中可以同時(shí)存在global和scoped的樣式,即允許聲明兩個(gè)style標(biāo)簽。
<style> /* global styles */ </style> ? <style scoped> /* local styles */ </style>
使用Scoped CSS以后,因?yàn)闃邮骄哂辛俗饔糜?,所以父組件的樣式是不會(huì)影響到子組件的,即父組件和子組件的樣式都具有自己的作用域。
但是對(duì)于子組件的根元素來(lái)說(shuō),其樣式還是可以受父組件控制的,使得父組件可以控制布局。
- 注意通過(guò)v-html創(chuàng)建的DOM內(nèi)容是不受Scoped CSS控制的,如果希望修改其中的樣式,可以通過(guò)深度作用選擇器。
- 因?yàn)镾coped CSS是通過(guò)屬性選擇器實(shí)現(xiàn)的,所以最好不要和標(biāo)簽選擇器混用,會(huì)產(chǎn)生性能問(wèn)題。
深度作用選擇器
- 深度作用選擇器使得父組件的樣式可以滲透到子組件,其原理是使用后代選擇器。
/* 轉(zhuǎn)化前 */ <style scoped> .a :deep(.b) { /* ... */ } </style> ? /* 轉(zhuǎn)化后 */ .a[data-v-f3f3eg9] .b { /* ... */ }
需要注意深度作用選擇器和聲明為global樣式的區(qū)別,深度作用選擇器只是為了能讓父組件控制子組件樣式,而global樣式是全局起效的。
實(shí)際項(xiàng)目中,當(dāng)我們希望修改所使用組件庫(kù)的默認(rèn)樣式時(shí),在使用Scoped CSS方案的情況下,就可以通過(guò)深度作用選擇器來(lái)修改其默認(rèn)樣式。
幾種深度左右選擇器的寫法:
- /deep/:已廢棄
- >>>:在不使用Sass預(yù)處理器時(shí)可以使用
- ::v-deep:使用Sass預(yù)處理器時(shí)使用
Vue3新特性
深度作用選擇器
廢棄/deep和>>>,使用:deep(.child-class)來(lái)替代::v-deep
:slotted()選擇器
支持使用:slotted(selector)來(lái)控制slot中的樣式
:global()選擇器
當(dāng)只有某些規(guī)則需要全局起效時(shí),允許不重復(fù)聲明一個(gè)全局作用域的style標(biāo)簽,而是使用:global(selector)來(lái)聲明為全局樣式。
二者的比較
CSS Modules | Scoped CSS |
---|---|
需要在vue.config.js中額外配置 | Vue Loader默認(rèn)支持,無(wú)需額外配置 |
通過(guò)根據(jù)配置的類命名規(guī)則,為元素生成獨(dú)一無(wú)二的類名來(lái)實(shí)現(xiàn)作用域隔離 | 通過(guò)給元素自定義hash屬性,再使用屬性選擇器選中元素來(lái)實(shí)現(xiàn)作用域隔離 |
在style標(biāo)簽中聲明module | 在style標(biāo)簽中聲明scoped |
支持導(dǎo)入其他module的樣式,支持樣式組合 | / |
通過(guò):global()來(lái)解除作用域的隔離,使樣式在全局生效 | 1. 可以定義全局樣式,使樣式不受作用域約束;2. 可以通過(guò)深度作用選擇器命中子組件,從而控制子組件的樣式 |
總結(jié)
到此這篇關(guān)于Vue項(xiàng)目中CSS Modules和Scoped CSS的介紹與區(qū)別的文章就介紹到這了,更多相關(guān)Vue中CSS Modules和Scoped CSS內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue+Element UI 樹形控件整合下拉功能菜單(tree + dropdown +input)
這篇文章主要介紹了Vue+Element UI 樹形控件整合下拉功能菜單(tree + dropdown +input)的方法,幫助大家更好的理解和學(xué)習(xí)vue,感興趣的朋友可以了解下2020-08-08vue實(shí)現(xiàn)點(diǎn)擊選中,其他的不選中方法
今天小編就為大家分享一篇vue實(shí)現(xiàn)點(diǎn)擊選中,其他的不選中方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-09-09解決Vue開發(fā)中對(duì)話框被遮罩層擋住的問(wèn)題
在Vue的開發(fā)中,一旦我們用到對(duì)話框,經(jīng)常出現(xiàn)的問(wèn)題是對(duì)話框被遮罩層擋住,怎么來(lái)解決這個(gè)問(wèn)題呢?下面小編給大家?guī)?lái)了Vue開發(fā)中對(duì)話框被遮罩層擋住的問(wèn)題及解決方法,一起看看吧2018-11-11vue3中的elementPlus全局組件中文轉(zhuǎn)換方式
這篇文章主要介紹了vue3中的elementPlus全局組件中文轉(zhuǎn)換方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07Vue3中按需引入ECharts詳細(xì)步驟(一看就會(huì))
新項(xiàng)目采用Vue3作為前端項(xiàng)目框架,避免不了要使用echarts,這篇文章主要給大家介紹了關(guān)于Vue3中按需引入ECharts的相關(guān)資料,需要的朋友可以參考下2023-09-09