vue3学习记录-单文件组件 CSS 功能
- 1.组件作用域 CSS
- 1.1为什么要用到样式穿透(:deep())
- 1.2 插槽选择器:slotted(div)
- 1.3 全局选择器:global
- 2.CSS Modules
- 2.1 基本用法
- 2.2 自定义注入名称
- 2.3 与组合式 API 一同使用
- 3.CSS 中的 v-bind()
1.组件作用域 CSS
1.1为什么要用到样式穿透(:deep())
在用一些ui框架,例如elementui的时候,再加上style加了scoped属性导致,正常的写法是改变不了其中的一些css,为什么呢?因为scoped,
- 给HTML的DOM节点加一个不重复data属性(形如:data-v-123)来表示他的唯一性
2.在每句css选择器的末尾(编译后的生成的css语句)加一个当前组件的data属性选择器(如[data-v-123])来私有化样式
3.如果组件内部包含有其他组件,只会给其他组件的最外层标签加上当前组件的data属性
例如,当前的App.vue文件
<script setup>
</script><template><div><p>{{ $hello('Vue') }}</p><input type="text" v-focus><el-select v-model="bb"><el-option label="选项1" value="1"></el-option><el-option label="选项2" :value="2"></el-option></el-select><global-component></global-component><button @click="showMessage">显示消息</button></div>
</template>
<style scoped lang="scss">
.el-select{width: 200px;.el-select__wrapper{background-color: aqua;}
}
</style>
当前template里的html渲染出来都会带上一个不重复的data属性
而且el-select组件下面的标签是没有带不重复的data属性的。而且当前的.el-select[data-v-7a7a37b1]也是class名加上data属性去命中对应的class名。但是为什么写的 .el-select__wrapper{background-color: aqua;}样式没生效呢,而且原有的样式
也没有我自己写的.el-select{.el-select__wrapper{ }}权重高吧,但是就是没生效。我们看看浏览器中的class文件
可以看到el-select的样式现在在scoped的作用下是根据.select加data属性来命中css的,这个是有的。但是.el-select__wrapper的样式是.el-select .el-select__wrapper[data-v-7a7a37b1] ,第一个.el-select就对应不上的,所以写的el-select__wrapper自然也对应不上。所以用到了样式穿透。vue3使用的是:deep()
<style scoped lang="scss">
.el-select{width: 200px;:deep(.el-select__wrapper){background-color: aqua;}
}
</style>
效果:
:deep()帮我们把原有的.el-select .el-select__wrapper[data-v-7a7a37b1] 变成了.el-select[data-v-7a7a37b1] .el-select__wrapper。所以样式能对应上
1.2 插槽选择器:slotted(div)
//父组件
<template><A><div class="demo">aaa</div></A>
</template><style scoped>
.demo{color: red;
}
</style>
//子组件<template><div class="container"><slot></slot></div>
</template><script setup></script>
<style lang='scss' scoped>
.container {width: 200px;height: 200px;background-color: lightcoral;margin-bottom: 10px;:slotted(.demo) {color: lightblue;}
}
</style>
这里渲染出来的结果是以带了子组件的color为重,
但是如果把:slotted去掉的话,color就是以父组件的为主了.container 样式去掉的话,
<style lang='scss' scoped>:slotted(.demo) {color: lightblue;}
</style>
却是以父组件的样式为主。
感觉:slotted的作用是能让子组件的插槽有一些默认的css样式,当然权重的就是另外的结果。
1.3 全局选择器:global
顾名思义,就是在当前组件创建一个其他组件也能访问到的css样式
//父
<script setup>
import A from './components/A.vue';
import B from './components/B.vue';
</script><template><A></A>
</template><style scoped>:global(.demo) {color: red;
}
</style>
//子
<template><div class="container"><a href="" class="demo">试一试全局的css</a><slot></slot></div>
</template>
子组件的字体是红色的。
2.CSS Modules
2.1 基本用法
一个
<template><p :class="$style.red">This should be red</p>
</template><style module>
.red {color: red;
}
</style>
得出的 class 将被哈希化以避免冲突,实现了同样的将 CSS 仅作用于当前组件的效果。
2.2 自定义注入名称
你可以通过给 module attribute 一个值来自定义注入 class 对象的属性名:
<template><p :class="classes.red">red</p>
</template><style module="classes">
.red {color: red;
}
</style>
2.3 与组合式 API 一同使用
import { useCssModule } from 'vue'// 在 setup() 作用域中...
// 默认情况下,返回 <style module> 的 class
useCssModule()// 具名情况下,返回 <style module="classes"> 的 class
useCssModule('classes')//测试
<script setup>
import { useCssModule } from 'vue'const classes = useCssModule('classes')
console.log(classes)
console.log(classes.red)</script><style module="classes">
.red {color: red;
}.green {color: green;.aa {color: yellow;}
}
</style>
结果:
返回当前type modules里面定义的class的原class名和渲染在浏览器的对应css名的映射对象。如果你想再进行后续的操作,例如在某些情况下,你可能需要将你的 Vue 组件与一些第三方 JavaScript 库或框架集成。这些库可能需要你提供元素的类名来进行操作。此时,你可以使用 useCssModule 提供的映射类名来确保正确地引用到对应的元素。
3.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>
import { ref } from 'vue'
const theme = ref({color: 'red',
})
</script><template><p>hello</p><button @click="theme.color = 'blue'">改变颜色</button>
</template><style scoped>
p {color: v-bind('theme.color');
}
</style>
实际的值会被编译成哈希化的 CSS 自定义属性,因此 CSS 本身仍然是静态的。感觉是在中间找了个中间变量。自定义属性会通过内联样式的方式应用到组件的根元素上,并且在源值变更的时候响应式地更新。
点击,确实中间变量属性名对应的值也改变了。