1、css深度选择器
scoped原理:
vue中的scoped 通过在DOM结构以及css样式上加唯一不重复的标记:data-v-hash的方式,以保证唯一(而这个工作是由过PostCSS转译实现的),达到样式私有化模块化的目的。
总结一下scoped三条渲染规则:
- 给HTML的DOM节点加一个不重复data属性(形如:data-v-123)来表示他的唯一性
- 在每句css选择器的末尾(编译后的生成的css语句)加一个当前组件的data属性选择器(如[data-v-123])来私有化样式
- 如果组件内部包含有其他组件,只会给其他组件的最外层标签加上当前组件的data属性
保留scoped属性,使用深度选择器,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <!-- 写法1 使用::v-deep --> <style lang="scss" scoped> ::v-deep .el-input__inner{ background: yellowgreen; } </style> <!-- 写法2 使用>>> 操作符--> <style scoped> >>>.el-input__inner{ background: yellowgreen; } </style> <!-- 写法3 使用/deep/ --> <style scoped> /deep/.el-input__inner{ background: yellowgreen; } </style> <!-- 写法4 使用:deep(<inner-selector>) --> <style lang="scss" scoped> :deep(.el-input__inner){ background: yellowgreen; } </style>
|
使用深度选择器后代码被编译成如下形式:
1 2 3
| [data-v-e44d851a] .el-input__inner { background: yellowgreen; }
|
Ps:
写法1 和写法4,都支持sass预处理器。但是在新的vue3.0 单文件规范中,如果你还是使用写法1,会碰到如下警告:
1
| [@vue/compiler-sfc] ::v-deep usage as a combinator has been deprecated. Use :deep(<inner-selector>) instead.
|
写法1在vue3.0中已经被弃用了,在开发vue3.0项目的时候,还是使用写法4,写法4在语义上也更有助于理解。
写法1和写法3,主要是不支持sass预处理器的解析,且>>>
操作符存在浏览器兼容性问题
2、:slotted(inner-selector)插槽选择器
子组件定义插槽
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| <!-- * @Description: * @Author: xiuji * @Date: 2022-09-07 17:49:20 * @LastEditTime: 2022-09-14 11:21:58 * @LastEditors: Do not edit --> <template> <div class="slot"> <header class="header"> <!-- slot标签相当于一个占位符 --> <slot name="header"></slot> </header> <main class="main"> <!-- slot标签相当于一个占位符 --> <div> <div v-for="i in 100"> <slot :data="i"></slot> </div> </div> </main> <footer class="footer"> <!-- slot标签相当于一个占位符 --> <slot name="footer"></slot> </footer>
</div> </template>
<script setup lang="ts">
</script>
<style lang="scss" scoped> .header { height: 200px; background-color: aqua; }
.main { height: 300px; background-color: bisque; }
.footer { height: 200px; background-color: cadetblue; } </style>
|
父组件使用该子组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| <!-- * @Description: * @Author: xiuji * @Date: 22022-11-20 09:14:30 * @LastEditTime: 2022-12-13 15:09:49 * @LastEditors: Do not edit --> <template> <div class="content"> 下面是插槽 <Slot> <template #header> <div class="test_change">2222</div> </template> </Slot> </div> </template>
<script setup lang="ts"> import Slot from '../../components/Slot/index.vue' </script>
<style lang="scss" scoped> .content { position: relative; flex: 1; height: 100%; margin: 20px; border: 1px solid #ccc; overflow: auto; } </style>
|
子组件中修改插槽class的颜色
1 2 3 4 5
| <style lang="less" scoped> .test_change { color:greenyellow; } </style>
|
未能修改,作用域样式不会影响到 <slot/>
渲染出来的内容,因为它们被认为是父组件所持有并传递进来的。
解决方案:
1 2 3 4 5
| <style lang="less" scoped> :slotted(.test_change) { color:greenyellow; } </style>
|
3、:global(inner-selector)全局选择器
通常都是通过新建一个不加scoped属性的style标签修改全局样式,现在有更优雅的方案——:global()
1 2 3 4 5
| <style lang="less" scoped> :global(div){ color:red } </style>
|
4、:v-bind(inner-selector)动态css
单文件组件的 <style>
标签可以通过 v-bind
这一 CSS 函数将 CSS 的值关联到动态的组件状态上:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| <!-- * @Description: * @Author: xiuji * @Date: 2022-09-07 17:49:20 * @LastEditTime: 2022-12-13 16:00:08 * @LastEditors: Do not edit --> <template> <div class="slot"> <header class="header"> <!-- slot标签相当于一个占位符 --> <slot name="header"></slot> </header> <main class="main"> <!-- slot标签相当于一个占位符 --> <div> <div v-for="i in 100"> <slot :data="i"></slot> </div> </div> </main> <footer class="footer"> <!-- slot标签相当于一个占位符 --> <slot name="footer"></slot> </footer>
</div> </template>
<script setup lang="ts"> import { ref } from 'vue'; const changeColor = ref<string>('aqua') </script>
<style lang="scss" scoped> .header { height: 200px; background-color: v-bind(changeColor); // 使用变量动态修改css样式 }
.main { height: 300px; background-color: bisque; }
.footer { height: 200px; background-color: cadetblue; } </style>
|
如果是对象形式的变量,v-bind需要加引号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| <!-- * @Description: * @Author: xiuji * @Date: 2022-09-07 17:49:20 * @LastEditTime: 2022-12-27 10:13:28 * @LastEditors: Do not edit --> <template> <div class="slot"> <header class="header"> <!-- slot标签相当于一个占位符 --> <slot name="header"></slot> </header> <main class="main"> <!-- slot标签相当于一个占位符 --> <div> <div v-for="i in 100"> <slot :data="i"></slot> </div> </div> </main> <footer class="footer"> <!-- slot标签相当于一个占位符 --> <slot name="footer"></slot> </footer>
</div> </template>
<script setup lang="ts"> import { ref,reactive } from 'vue'; const changeColor = ref<string>('aqua') type obj = { color:string } const objColor = reactive<obj>({ color: 'bisque' })
</script>
<style lang="scss" scoped> .header { height: 200px; background-color: v-bind(changeColor); // 使用变量动态修改css样式 }
.main { height: 300px; background-color: v-bind('objColor?.color'); // 对象形式的变量,v-bind需要加引号 }
.footer { height: 200px; background-color: cadetblue; } </style>
|
5、css module
<style module>
标签会被编译为CSS Modules并且将生成的CSS类作为$style对象的键暴露给组件
1 2 3 4 5 6 7 8 9 10 11 12
| <template> <div :class="$style.red"> test css module </div> </template> <style module> .red { color: red; font-size: 20px; } </style>
|
自定义注入名称,多个可用数组,可以通过module attribute一个参数来自定义注入的类对象的property键
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <template> <div :class="[xj.red,xj.border]"> test moudule attribute </div> </template> <style module="xj"> .red { color: red; font-size: 20px; } .border{ border: 1px solid #ccc; } </style>
|
与组合式API一同使用
注入的类可以通过 useCssModule API 在 setup()
和 <script setup>
中使用。对于使用了自定义注入名称的 <style module>
模块,useCssModule
接收一个对应的 module
attribute 值作为第一个参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <template> <div :class="[xj.red,xj.border]"> 小满是个弟弟 </div> </template> <script setup lang="ts"> import { useCssModule } from 'vue' const css = useCssModule('xj') </script> <style module="xj"> .red { color: red; font-size: 20px; } .border{ border: 1px solid #ccc; } </style>
|
一般TSX 和 render函数使用场景居多