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...