A CSS Moduleis a CSS file in which all class names and animation names are scoped locally by default. All URLs (url(...)
) and@imports
are in module request format (./xxx
and../xxx
means relative,xxx
andxxx/yyy
means in modules folder, i. e. innode_modules
).
CSS
模塊是一個CSS
文件,默認狀況下,全部類名和動畫名都在本地做用域內。全部URL(url(...))
和@imports
均以模塊請求格式表示(./ xxx
和../ xxx
表示相對,xxx
和xxx / yyy
表示模塊文件夾,即在「 node_modules」
中)。css
也就是說,css modules
是主要爲了解決樣式衝突問題,使得css
樣式具備做用域。html
vue項目中有兩種解決css衝突的方案,一種是比較常見的使用scoped。另外一種就是css modules。先對這兩種方案原理作一個簡單介紹,而後比較他們之間的區別:vue
這是在vue項目中很是常見的解決樣式衝突方式,當在style標籤中加上scoped,編譯後會在該vue組件元素上加上hash標識屬性,在vue組件裏的每一個元素都有同一個hash標識屬性。沒法徹底避開css權重和類名重複的問題。node
實例算法
<style scoped> .example { color: red; } </style> <template> <div class="example">hi</div> </template>
編譯後數組
<style> .example[data-v-f3f3eg9] { color: red; } </style> <template> <div class="example" data-v-f3f3eg9>hi</div> </template>
產生局部做用域的惟一方法,就是使用一個獨一無二的class
的名字,爲全部類名從新生成類名,有效避開了css權重和類名重複的問題,這就是 CSS Modules 的作法。css module直接替換了類名,排除了用戶設置類名影響組件樣式的可能性sass
實例安全
<style module> .red { color: red; } </style> <template> // 構建工具會將類名`style.red`編譯成一個哈希字符串,這樣一來,這個類名就變成獨一無二了,只對對應組件有效。 <p :class="$style.red"> This should be red </p> </template>
編譯後app
<style module> ._1yZGjg0pYkMbaHPr4wT6P__1 { color: red; } </style> <template> <p class="_1yZGjg0pYkMbaHPr4wT6P__1"> This should be red </p> </template>
//Father.vue <template> <div> <son></son> </div> </template> <script> import Son from './Son' export default { name: 'Father', components: { Son }, data () { return {} } } </script> <style scoped> .wrapper { width: 300px; height: 300px; line-height: 300px; vertical-align: middle; background-color: #000; color: #fff; } </style>
// Son.vue <template> <div class="wrapper">111111</div> </template> <script> export default { name: 'Son', data () { return {} } } </script>
Father組件的wrapper樣式會滲透到Son組件中並起做用!工具
>>>
鏈接符(或者 /deep/
)實現。但是別忘記,咱們卻所以失去了組件的封裝效果。這個組件內的全部的被父組件深度選擇器選擇的類的樣式都會被浸染——即使是孫節點。而css modules方案下全部的 CSS 類能夠經過$style
對象獲取到,因此咱們能夠經過 props 將這些類傳遞到任何咱們但願的深度中,這樣,在子組件中的任意位置使用這些類就會變得極其容易// Father.vue <template> <div> <son :contentClass="$style.content"></son> </div> </template> <script> import Son from './Son' export default { name: 'Father', components: { Son }, data () { return {} } } </script> <style lang="scss" module> .content { color: blue; } </style>
// Son.vue <template> <div :class="$style.wrapper"> <span :class="contentClass">111111</span> </div> </template> <script> export default { name: 'Son', props: ['contentClass'], data () { return {} } } </script> <style lang="scss" module> .wrapper { width: 300px; height: 300px; line-height: 300px; vertical-align: middle; background-color: #000; color: #fff; } </style>
效果:
{ test: /\.(sc|sa|c)ss$/, include: [path.join(__dirname, '.././', 'src')], // 匹配規則時,只使用第一匹配的數組 oneOf: [ // 這裏匹配 `<style module>` { // 與資源查詢匹配的條件 resourceQuery: /module/, use: [ // module須要使用vue-style-loader 'vue-style-loader', { loader: 'css-loader', options: { // 開啓 CSS Modules modules: true, // 自定義生成的類名 localIdentName: '[name]_[local]_[hash:base64:5]' } }, 'sass-loader' ] }, // 這裏匹配普通的 `<style>` 或 `<style scoped>` { use: [ // scoped使用style-loader 'style-loader', 'css-loader', 'sass-loader' ] } ] }
其實兩種方案都很是簡單、易用,在某種程度上解決的是一樣的問題。 那麼你該選擇哪一種呢?
scoped 樣式的使用不須要額外的知識,給人溫馨的感受。它所存在的侷限,也正是它的使用簡單的緣由。它能夠用於支持小型到中型的應用。
在更大的應用或更復雜的場景中,這個時候,對於 CSS 的運用,咱們就會但願它更加顯式,擁有更多的控制權。雖然在模板中大量使用 $style
看起來並不那麼「性感」,但卻更加安全和靈活,爲此咱們只需付出微小的代價。還有一個好處就是咱們能夠用 JS 獲取到咱們定義的一些變量(如色彩值、樣式斷點),這樣咱們就無需手動保持其在多個文件中同步。
參考:
https://juejin.im/post/5b9556...
https://www.jianshu.com/p/255...
http://www.ruanyifeng.com/blo...