如何在VueJS单文件组件中正确使用“scoped”样式?

41

VueJS的文档表明,scoped应该将样式限制在组件内部。但是如果我创建两个具有相同baz样式的组件,它将从一个组件泄漏到另一个组件:

foo.vue

<template>
  <div class="baz">
    <Bar></Bar>
  </div>
</template>

<style scoped>
.baz {
  color: red;
}
</style>

bar.vue

<template>
  <div class="baz">bar</div>
</template>

<style scoped>
.baz {
  background-color: blue;
}
</style>

我希望baz在两个组件中是不同的。但是生成网页后,我发现蓝色背景上的红色文字,这意味着foo的作用域样式影响了bar组件。生成的代码如下:

<div class="baz" data-v-ca22f368>
  <div class="baz" data-v-a0c7f1ce data-v-ca22f368>
    bar
  </div>
</div>

正如您所看到的,“漏洞”是由VueJS通过在 bar 组件中指定两个数据属性而故意生成的。但是为什么呢?


这可能是一个特殊情况,因为这两个组件是嵌套的。不确定它是否符合错误的标准。 - cello
2个回答

60
您可以在Vue加载器文档中阅读:

子组件的根节点将受到父级作用域 CSS 和子级作用域 CSS 的影响。

尽管可能会有点令人困惑,但这显然是预期的行为。

如果您想避免这种情况,您应该使用CSS 模块

<template>
<div :class="$style.baz">
  <Bar></Bar>
</div>
</template>

<style module>
.baz {
  color: red;
}
</style>

35
做得好!这是一个非常令人印象深刻的翻译。上面引用的文件摘录非常难以理解,就像一个低分辨率的莫比乌斯环插图一样迷惑人心。 - AJB
这是否也可以表述为:“父组件的作用域样式仍将影响任何后代元素”?我是诚恳地询问。 - Jar
1
不完全是 @Jared 所说的。 "子组件的根节点" - 在子组件中 <template> 中的第一个元素,通常是一个 <div>。如果您将类移动到更低的级别,则可以避免样式的 "冲突"。 - Michal M.

2

2021

我发现一个答案,父组件的样式会应用于子组件,但只针对第一个直接子元素有效,例如当我们有一个按钮组件时:

<template>
   <button class='btn' />
</template>

通过这种方法,您可以从父级样式化btn类,以避免需要使用一些虚拟div包装btn组件,或者最好使用vue-fragment库,您将避免使用scoped属性时出现样式泄漏问题。

<template>
   <fragment>
      <button class='btn' />
   </fragment>
</template>

这样做的话,您将无法在子组件中对btn类进行样式设置。
完整示例请参见: https://codesandbox.io/s/falling-fog-2mu5z?file=/src/components/HelloWorld.vue Vue片段: https://www.npmjs.com/package/vue-fragment

1
请查看此链接:https://www.telerik.com/blogs/understanding-vue-deep-css-selector - kenchilada
是的,我知道了。使用vuetify只需要使用::v-deep伪元素。非常好的文章,谢谢。 - Freestyle09

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接