scoped css
在Vue项目中,一般使用 scoped
属性来创建样式模块。带有scoped属性的样式模块只会作用于当前组件的元素。
CSS
<template>
<div class="example">
<p>这是一个段落</p>
</div>
</template>
<style scoped>
.example {
color: red;
}
</style>
最终页面效果如下:
这是借助vue-loader
和PostCSS
实现的.
不过这种方式存在缺陷: 如果你子组件的根元素上有一个类已经在这个父组件中定义过了,那么这个父组件的样式就会泄露到子组件中。例如:
Parent.vue
:
vue
<template>
<div class="container">
<p>parent</p>
<child />
</div>
</template>
<script>
import Child from "./components/Child";
export default {
name: "App",
components: {
Child,
},
};
</script>
<style scoped>
.container {
color: red;
border: 1px solid blue;
}
</style>
Child.vue
vue
<template>
<div class="container">
<p>child</p>
</div>
</template>
<script>
export default {
name: "HelloWorld",
};
</script>
<style scoped>
</style>
为什么Child
会受到Parent
样式的影响? 可以看到经过loader处理后的html代码如下,如果父子组件都使用了scoped,那子组件的根元素也会有父组件的data-v-hash
属性,会对子组件造成污染.
xml
<div data-v-4184d4e3 class="container">
<p data-v-4184d4e3>parent</p>
<div data-v-00d89a5e data-v-4184d4e3 class="container">
<p data-v-00d89a5e>child</p>
</div>
</div>
css moudle
vue
<template>
<div :class="$style.container">
<p>child</p>
</div>
</template>
<script>
export default {
name: "HelloWorld",
mounted() {
console.log(this.$style); // {container: '_src_components_Child__container'}
}
};
</script>
<style module>
.container {
color: green;
}
</style>
上面的模板在经过loader处理后的html为:
html
<div data-v-4184d4e3 class="_src_components_Child__container">
<p>child</p>
</div>
可以看到生成的class类名 _src_components_Child__container
为 文件路径+文件名+css类名
,确保了class类名不会重复. 在模板中可以通过$style
获取所有的样式.
可以明显看到使用css moudle的优点:
1、可以一眼看出样式属于哪个组件
2、不会让父组件的样式泄漏到子组件
实际上它还有一些其它的功能:
组合样式
对于样式复用,CSS Modules 只提供了唯一的方式来处理:composes
组合
css
/* components/Button.css */
.base { /* 所有通用的样式 */ }
.normal {
composes: base;
/* normal 其它样式 */
}
.disabled {
composes: base;
/* disabled 其它样式 */
}
import styles from './Button.css';
buttonElem.outerHTML = `<button class=${styles.normal}>Submit</button>`
由于在 .normal
中 composes
了 .base
,编译后会 normal
会变成两个 class
html
<button class="button--base-daf62 button--normal-abc53">Submit</button>
composes
还可以组合外部文件中的样式
css
/* settings.css */
.primary-color {
color: #f40;
}
/* components/Button.css */
.base { /* 所有通用的样式 */ }
.primary {
composes: base;
composes: primary-color from './settings.css';
/* primary 其它样式 */
}
通过 :global
声明为全局样式
css
:global {
.global-class-name {
color: green;
}
}
在webpack中配置css moudle
只使用css moudle:
javascript
{
module: {
rules: [
// ... 其它规则省略
{
test: /.css$/,
use: [
'vue-style-loader',
{
loader: 'css-loader',
options: {
// 开启 CSS Modules
modules: true,
// 自定义生成的类名
localIdentName: '[local]_[hash:base64:8]'
}
}
]
}
]
}
}
同时使用scope和css moudle:
perl
// webpack.config.js -> module.rules
{
test: /.css$/,
oneOf: [
// 这里匹配 `<style module>`
{
resourceQuery: /module/,
use: [
'vue-style-loader',
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[local]_[hash:base64:5]'
}
}
]
},
// 这里匹配普通的 `<style>` 或 `<style scoped>`
{
use: [
'vue-style-loader',
'css-loader'
]
}
]
}