关于vue scoped深入交流分析

不小心分析一波scoped

第一回合

父组件

<template>
  <div class="gis-main">
    <div class="akin-text">父组件定义的灰色</div>
    <text-color></text-color>
  </div>
</template>

<script setup>
import TextColor from './text.vue';
</script>
<style lang="less" scoped>
.akin-text {
  margin: 5px 0 0;
  background: #ccc; // 改变该class颜色
}
</style>

子组件

<script setup lang="ts"></script>

<template>
  <div class="akin-text">子组件定义的红色</div>
</template>

<style lang="less" scoped>
.akin-text {
  margin: 5px 0 0;
  background: #ff0000; // 在子组件中定义颜色
}
</style>

结果

子组件不生效

image

第二回合

父组件不变

子组件加了个空标签

<script setup lang="ts"></script>

<template>
  <div class="akin-text">子组件定义的红色</div>
  <div></div>
</template>

<style lang="less" scoped>
.akin-text {
  margin: 5px 0 0;
  background: #ff0000;
}
</style>

结果

子组件生效

image

WHY?TELL ME WHY?

第三回合

回到第一回合。增加子标签,不同的CSS修改

<template>
  <div class="gis-main">
    <div class="akin-text">父组件定义的灰色<span class="text_red">里面的字 </span></div>
    <text-color></text-color>
  </div>
</template>

<script setup>
import TextColor from './text.vue';
</script>
<style lang="less" scoped>
.akin-text {
  margin: 5px 0 0;
  background: #ccc;
  .text_red {
    color: #00ff00;
  }
}
</style>

<script setup lang="ts"></script>

<template>
  <div class="akin-text">子组件定义的红色<span class="text_red"> 里面的字 </span></div>
</template>

<style lang="less" scoped>
.akin-text {
  margin: 5px 0 0;
  background: #ff0000;
  .text_red {
    color: #ff0000;
  }
}
</style>

结果

顶层标签不生效,内标签生效

image

分析代码

未加标签的时候

image

增加空标签之后

image

发现现象:

加了空标签之后,只有一个data-v了,未加的时候,是两个data-v

所以猜测根节点的时候,解析异常

然后在官方文档中找到:

使用 scoped 后,父组件的样式将不会渗透到子组件中。不过,子组件的根节点会同时被父组件的作用域样式和子组件的作用域样式影响。这样设计是为了让父组件可以从布局的角度出发,调整其子组件根元素的样式。

但是只影响子组件的根节点。不影响根节点里面的标签

然后在官方文档接着扒

当我在一个组件中的style里面加了scoped之后生成的css是这样的

.akin-text .text_red[data-v-06dcf99e]

但是有时候需要控制到下级,需要生成这样的,怎么办

.akin-text[data-v-c248bd1d] .text_red
深度选择器生成这样的
.a :deep(.b){ }

v-html的不会受影响,因为他不会有data-v属性

当然样式隔离你也可以用css module

<template>
  <div class="gis-main">
    <div :class="$style.akin">父组件定义的灰色<span class="text_red">里面的字 </span></div>
    <text-color></text-color>
  </div>
</template>

<script setup>
import TextColor from './text.vue';
</script>
<style module lang="less" scoped>
.akin {
  margin: 5px 0 0;
  background: #ccc;
}
</style>

结果

image

新建一个全局样式

方法一:style不加scoped

方法二::global(.class)

最终都会生成一个

.class{
  background:#f00
}

修改插槽过来的组件的样式

slotted

会生成一个data-v-xxxx-s的样式

.class[data-v-06dcf99e-s]

最后,官方的

  • 作用域样式并没有消除对 class 的需求。由于浏览器渲染各种各样 CSS 选择器的方式,p { color: red } 结合作用域样式使用时 (即当与 attribute 选择器组合的时候) 会慢很多倍。如果你使用 class 或者 id 来替代,例如 .example { color: red },那你几乎就可以避免性能的损失。
  • 小心递归组件中的后代选择器!对于一个使用了 .a .b 选择器的样式规则来说,如果匹配到 .a 的元素包含了一个递归的子组件,那么所有的在那个子组件中的 .b 都会匹配到这条样式规则。

我的:

  • 样式穿透问题: 虽然 scoped 可以有效地将样式隔离到组件作用域内,但有时候你可能希望样式能够跨越组件边界影响其他组件中的元素。在这种情况下,scoped 的限制可能会成为问题,需要使用深度选择器来绕过这个限制,但这可能会导致样式变得复杂难以维护。
  • 全局样式覆盖困难: 在某些情况下,你可能需要在全局范围内覆盖组件中的样式,但由于 scoped 的隔离性,直接覆盖样式可能会变得困难。解决这个问题的方式通常是使用特定的 CSS 类名或选择器,但这可能会增加样式的复杂性。
  • 样式的优先级: 当在组件中使用 scoped 样式时,你可能会遇到样式的优先级问题,特别是当你在使用深度选择器时。这可能需要更多的注意力来管理样式的权重和优先级,以避免不必要的冲突。

所以

关于命名

BEM一种css命名方法论,意思是块(Block)、元素(Element)、修饰符(Modifier)的简写

B-E_m

不要用ID

不要用标签选择器

简写

image