Vue中的CSS Deep

发布时间:2023-05-21

一、深入了解CSS Deep

CSS deep或者叫做/deep/>>>::v-deep,用于给子组件的样式添加一个全局作用域。在Vue中,它被广泛运用在scoped CSS中,以扩大样式的作用范围。 举个例子,在Vue的组件中添加<style scoped>样式如下:

<template>
  <div class="parent">
    <div class="child">I am a child</div>
  </div>
</template>
<script>
export default {
  name: 'ParentComponent'
}
</script>
<style scoped>
.parent {
  color: blue;
}
.child {
  font-size: 20px;
}
</style>

样式在组件中会被编译成如下代码:

.parent[data-v-f3f3eg9] {
  color: blue;
}
.parent[data-v-f3f3eg9] .child {
  font-size: 20px;
}

这时候,如果要给子组件的样式添加和父组件同样的scoped样式,只需要在子组件中添加/deep/或者>>>,如下:

<template>
  <div class="parent">
    <ChildComponent />
  </div>
</template>
<script>
import ChildComponent from './ChildComponent.vue'
export default {
  name: 'ParentComponent',
  components: { ChildComponent }
}
</script>
<style scoped>
.parent {
  color: blue;
}
/deep/ .child {
  font-size: 20px;
}
</style>

这样,子组件的样式就会被编译成如下代码:

.parent[data-v-f3f3eg9] {
  color: blue;
}
.parent[data-v-f3f3eg9] .child[data-v-f3f3eg9] {
  font-size: 20px;
}

二、解决scoped CSS样式穿透问题

在Vue中,scoped CSS可以保证组件的样式不会影响到其他组件,但是也有可能会碰到需要影响到其他组件的情况。这时候,可以使用CSS deep来解决scoped CSS样式穿透问题。 例如,父组件和子组件都有自己的样式,但是需要影响到另一个组件。这时候使用CSS deep可以轻松实现,如下:

<template>
  <div class="parent">
    <p class="parent-text">I am a parent</p>
    <div class="child">
      <p class="child-text">I am a child</p>
      <GrandchildComponent />
    </div>
  </div>
</template>
<script>
import GrandchildComponent from './GrandchildComponent.vue'
export default {
  name: 'ParentComponent',
  components: { GrandchildComponent }
}
</script>
<style scoped>
.parent {
  color: blue;
}
.child {
  font-size: 20px;
}
/deep/ .grandchild {
  font-weight: bold;
}
</style>
<!--在GrandchildComponent.vue中-->
<template>
  <div class="grandchild">
    <p class="grandchild-text">I am a grandchild</p>
  </div>
</template>
<script>
export default {
  name: 'GrandchildComponent'
}
</script>
<style scoped>
.grandchild {
  color: red;
}
/deep/ .parent-text {
  font-style: italic;
}
</style>

这样,.grandchild样式就只会作用在GrandchildComponent组件内,而/deep/ .parent-text样式可以修改父组件的样式。

三、推荐使用CSS modules替换CSS deep

虽然CSS deep可以扩大组件中样式的作用范围,但是容易造成全局样式混乱和耦合,所以在实际开发中,推荐使用CSS modules替换CSS deep。 CSS Modules是一种基于CSS的加载器,在编写CSS时可以局部作用域,解决了全局作用域的冲突问题,避免了CSS混乱的情况。 在Vue项目中使用CSS modules非常方便,只需要在<style>标签中添加module即可:

<template>
  <div class="parent">
    <p class="parent-text">I am a parent</p>
    <div class="child">
      <p class="child-text">I am a child</p>
      <GrandchildComponent />
    </div>
  </div>
</template>
<script>
import GrandchildComponent from './GrandchildComponent.vue'
export default {
  name: 'ParentComponent',
  components: { GrandchildComponent }
}
</script>
<style module>
.parent {
  color: blue;
}
.child {
  font-size: 20px;
}
.grandchild {
  color: red;
}
.parentText {
  font-style: italic;
}
</style>

然后在组件中使用样式,只需要在样式后添加$style,如:

<template>
  <div :class="$style.parent">
    <p :class="$style.parentText">I am a parent</p>
    <div class="child">
      <p class="child-text">I am a child</p>
      <GrandchildComponent />
    </div>
  </div>
</template>
<script>
import GrandchildComponent from './GrandchildComponent.vue'
export default {
  name: 'ParentComponent',
  components: { GrandchildComponent }
}
</script>
<style module>
.child {
  font-size: 20px;
}
.grandchild {
  color: red;
}
.parentText {
  font-style: italic;
}
</style>

这样,在编写CSS时就不需要担心全局作用域问题,同时也提供了更好的可维护性。