• **scoped: **仅影响当前组件下所有DOM节点、子组件根节点;
  • 非scoped: 影响整个页面下所有DOM节点;(即会影响页面内其他组件下的DOM节点);
  • 组件内隔离方案: style声明为module,且在HTML节点上使用:class="[$style.class1, .., $style.classN]";
  • 为避免受父组件样式影响,创建组件叶,应使用空样式div包含有效DOM元素;

1 scoped原理

场景:需要修改当前组件,或子组件根节点的样式,同时不影响页面内其他组件样式

  • vue给所有声明scoped组件的根节点,生成一个全局唯一的data属性(格式:data-v-[hash]);
  • 该组件的data属性会被添加至组件内所有的DOM节点(包含子组件的根节点);
  • 在scoped内的css选择器末尾(编译后的css),添加一个当前组件data属性选择器;

2 深度选择器:deep()

场景:修改子组件样式,同时不影响页面内其他使用该子组件的样式

方法:scoped + :deep()

<template>
  <div class="root">
    <el-input />
  </div>
</template>

<style lang="scss" scoped>
.root {
  .el-input__inner {
    /* 编译结果:.root .el-input__inner[data-v-xxxx] 样式无效 */
    background-color: pink;
  }

  :deep(.el-input__inner) {
    /* 编译结果:.root[data-v-xxxx] .el-input__inner 样式生效 */
    background-color: red;
  }
}
</style>

3 插槽样式:slotted()

场景:在子组件内,定义slot样式

  • 父组件
<template>
	<ComponentA> 
    	<span class="red">插槽内容(红色,由:slotted()定义)</span> 
    </ComponentA>
</template>

<script setup lang="ts">
    import ComponentA from './ComponentA.vue';
</script>
  • 子组件
<template>
  <slot />
  <span class="red">子组件内容(默认颜色,不受影响)</span>
</template>

<style lang="scss" scoped>
:slotted(.red) {
  color: red;
}
</style>
  • 效果

4 全局样式:global()

场景:定义全局样式

<style lang="scss" scoped>
:global(div) {
  color: red;
}

/* 等价于 */
div {
  color: red;
}
</style>

5 动态css(v-bind)

场景:绑定js变量

<script setup lang="ts">
import { ref } from 'vue';

const colorRed = ref('red');
const color = ref({
  red: 'red',
  green: 'green',
});
</script>

<style lang="scss" scoped>
.demo {
  color: v-bind(colorRed);
  background: v-bind('color.green'); // 对象要加 ''
}
</style>

6 CSS隔离 module

场景:CSS样式仅限组件内有效

方法:style声明为module,并且在DOM节点使用 :class="$style.root":class="[$style.root, $style.demo]"

<template>
  <div :class="[$style.root, $style.demo]">
      仅组件内有效,不影响页面内其他class="demo"组件的样式
  </div>
</template>

<style lang="scss" module>
.root {
  background-color: gray;
}
.demo {
  color: red;
}
</style>