简言
总结下vue3中组件的css用法。
css作用域
在vue组件中,可以像下面这样编写css:
<style>
/* 全局样式 */
</style>
<style scoped>
/* 局部样式 */
</style>
第一个是全局作用域,在里面编写的css内容加载后将会在所有页面内生效。
第二个是 局部作用域,style标签添加scoped属性时,它的 CSS 只会影响当前组件的元素,和 Shadow DOM 中的样式封装类似。使用时有一些注意事项,不过好处是不需要任何的 polyfill。它的实现方式是通过 PostCSS 将以下内容:
<style>
.example[data-v-f3f3eg9] {
color: red;
}
</style>
<template>
<div class="example" data-v-f3f3eg9>hi</div>
</template>
使用 scoped 后,父组件的样式将不会渗透到子组件中。不过,子组件的根节点会同时被父组件的作用域样式和子组件的作用域样式影响。这样设计是为了让父组件可以从布局的角度出发,调整其子组件根元素的样式。
局部作用域的一些用法
局部作用域虽然只能在单组件起作用,但你可以使用以下方法编写其他内容的css。
深度选择器
处于 scoped 样式中的选择器如果想要做更“深度”的选择,也即:影响到子组件,可以使用 :deep() 这个伪类:
<style scoped>
.a :deep(.b) {
/* ... */
}
</style>
上面的代码会被编译成:
.a[data-v-f3f3eg9] .b {
/* ... */
}
通过 v-html 创建的 DOM 内容不会被作用域样式影响,但你仍然可以使用深度选择器来设置其样式。
插槽选择器
默认情况下,作用域样式不会影响到 <slot/> 渲染出来的内容,因为它们被认为是父组件所持有并传递进来的。使用 :slotted 伪类以明确地将插槽内容作为选择器的目标:
<style scoped>
:slotted(div) {
color: red;
}
</style>
全局选择器
如果想让其中一个样式规则应用到全局,比起另外创建一个 <style>,可以使用 :global 伪类来实现 (看下面的代码):
<style scoped>
:global(.red) {
color: red;
}
</style>
CSS Modules
一个\
<template>
<p :class="$style.red">This should be red</p>
</template>
<style module>
.red {
color: red;
}
</style>
得出的 class 将被哈希化以避免冲突,实现了同样的将 CSS 仅作用于当前组件的效果。
自命名
你可以通过给 module attribute 一个值来自定义注入 class 对象的属性名:
<template>
<p :class="classes.red">red</p>
</template>
<style module="classes">
.red {
color: red;
}
</style>
与js使用
可以通过 useCssModule API 在 setup() 和 <script setup> 中访问注入的 class。对于使用了自定义注入名称的 <style module> 块,useCssModule 接收一个匹配的 module attribute 值作为第一个参数:
import { useCssModule } from 'vue'
// 在 setup() 作用域中...
// 默认情况下, 返回 <style module> 的 class
useCssModule()
// 具名情况下, 返回 <style module="classes"> 的 class
useCssModule('classes')
css使用js值(css中的v-bind)
单文件组件的\
<template>
<div class="text">hello</div>
</template>
<script>
export default {
data() {
return {
color: 'red'
}
}
}
</script>
<style>
.text {
color: v-bind(color);
}
</style>
这个语法同样也适用于 <script setup>,且支持 JavaScript 表达式 (需要用引号包裹起来):
<script setup>
const theme = {
color: 'red'
}
</script>
<template>
<p>hello</p>
</template>
<style scoped>
p {
color: v-bind('theme.color');
}
</style>
实际的值会被编译成哈希化的 CSS 自定义属性,因此 CSS 本身仍然是静态的。自定义属性会通过内联样式的方式应用到组件的根元素上,并且在源值变更的时候响应式地更新。
<script setup lang="ts">
const color = ref<string>("red");
</script>
<template>
<div>
<div class="text">this is one page!</div>
<button @click="color = 'blue'">改变color</button>
</div>
</template>
<style scoped>
.text {
color: v-bind(color);
}
</style>
结语
结束了。