组件样式

@Style
Fallthrough Attributes
父组件中,为只有一个根节点的子组件指定样式类 class 时,这个 class 会直接 叠加 到子组件的根节点上
这个样式类,既不是子组件定义的属性 props,也不是子组件抛出的 emits 事件,但是仍然传递给了子组件,所以称为属性透传
同样特点的属性还有内联样式 style、id 以及事件 v-on 等
更多信息,请访问 Fallthrough Attributes
样式属性透传
样式合并 - class and style Merging
子组件 - 具有唯一根节点,且指定样式类 reco
<template>
    <div class="reco">recommend</div>
</template>
父组件 - 引入并使用子组件,同时指定样式类 green
<template>
    <Reco class="green"></Reco>
</template>
最终渲染 - 同时带有样式类 reco 和 green;且 green 在 reco 后面 - merged with the class and style values that are inherited from the parent
<div class="reco green">recommend</div>
事件属性透传
属性透传同样适用事件 - same rule applies to v-on
先触发子组件的事件处理函数,再触发父组件的事件处理函数
子组件
<script setup>
    const say88 = () => {
        console.log('88')
    }
</script>

<template>
    <div @click="say88" class="reco">recommend</div>
</template>
父组件
<script setup>
    import Reco from './components/Reco.vue';
    const sayHi = () => {
        console.log('hi');
    };
</script>

<template>
    <Reco @click="sayHi"></Reco>
</template>
scoped
为 <style> 指定 scoped 时,它的 CSS 只会影响当前组件的元素
父组件的样式将不会 渗透 到子组件中。不过,子组件的根节点会同时被父组件的作用域样式和子组件的作用域样式影响。便于:让父组件可以从布局的角度出发,调整其子组件根元素的样式
更多作用域详细信息,请参考 类 classAPI - 单文件组件 CSS 功能
最佳体验:为组件的根节点指定与组件同名的样式类,很容易保证组件类的唯一性,且便于父组件布局
[] 版权组件结构
<template>
    <div class="copyright">
        <span class="txt">copyright @ 2024-2026</span>
        <slot></slot>
        <span class="txt">glpla.github.io</span>
    </div>
</template>
<style scoped>
</style>
父组件指定样式,如标签选择器 span 或类选择器 .txt 不会影响子组件内元素的样式 - 组件封装的特性
span {
    font-weight: 600;
}

.txt {
    color: #f40;
}
但是。但是。。但是。。。如果使用子组件根节点的类,则样式会生效
父组件设置子组件背景色;你可以这样理解:一般情况下,父组件仅能影响到子组件根节点
.copyright {
    background-color: #000;
}
插槽样式
[] 版权组件 - 默认插槽,这里以传递一个 <img> 为例
版权组件结构同上。版权组件仅仅是指定|预留了一个插槽
版权组件样式 - 无效;父组件使用这个插槽传递什么不确定;按F12在开发者视图中,检查元素页可以确定,没有样式
img {
    width: 30px;
    height: 30px;
    border-radius: 50%;
}
为插槽指定样式 avatar,同样无效
<template>
    <div class="copyright">
        <span>copyright @ 2024-2026</span>
        <slot class="avatar"></slot>
        <span>glpla.github.io</span>
    </div>
</template>
解决方案1 - 父组件指定样式,因为这个插槽是父组件提供的,对父组件是可见的;本质上还是父组件的,所以样式有效
父组件样式 - 有效
img {
    width: 30px;
    height: 30px;
    border-radius: 50%;
}
解决方案2 - 父组件使用特殊 伪类 选择器;更多选择器,请查看 HTML5选择器 - selector
特殊选择器
深度选择器 :deep(selector)
父组件如果想深入调整子组件内部元素的样式|影响到子组件,包括子组件的插槽元素,应使用伪类:deep(selector)
父组件使用深度选择器设置子组件内元素样式 - 父组件使用插槽,知道传递了什么元素,使用了什么选择器
:deep(img) {
    width: 30px;
    height: 30px;
}
插槽选择器 :slotted(selector)
默认情况下,作用域样式不会影响到 <slot/> 渲染出来的内容,因为它们被认为是父组件所持有并传递进来的
使用 :slotted 伪类以明确地将插槽内容作为选择器的目标
子组件使用插槽 标签 选择器 - Bad
:slotted(img) {
    width: 30px;
    height: 30px;
}
子组件使用插槽 类 选择器 - Good
:slotted(.avatar-img) {
    width: 30px;
    height: 30px;
}
但是。但是。。但是。。。子组件并不知道父组件到底使用插槽传递什么,你要预判所有的可能,写尽可能多的类样式
IDE可能会提示 ::slotted 而不是 :slotted。注意修正
开发规范的重要性
全局选择器 :global(selector)
如果想让其中一个样式规则应用到全局|扩大作用域,可以使用 :global(selector)
避免 这种情况出现。应该把全局类写到单独的样式文件中并全局引入 - 在哪里引入算是全局???
:global(.warn) {
    color: red;
}
以上选择器请仅在必要时使用,否则应寻求其它方法
还有一个样式穿透 >>>;注意当前框架是否支持
[] 项目 - 主页
提示:每一个子组件都使用根节点,且使用同组件名的类,便于父组件布局