前端学习笔记(四)自定义组件控制自己的css

发布于:2025-05-01 ⋅ 阅读:(15) ⋅ 点赞:(0)

1、前言及背景

自己写的一个组件有至少3个页面在使用,组件中的部分文字颜色需要统一修改需要根据一个状态字段来显示不同颜色且不希望受父组件影响
注意:博主学习vue截止目前也就半年,如有知识错误之处还请指出不胜感激,祝学习开心快乐哈哈

2、deepseek查询

提问:vue3中使用插槽时如果通过子组件统一设置父组件中的插槽的class
答案:
方案有2个
一、插槽包裹层样式穿透
通过在子组件中为插槽‌添加包裹容器‌并设置class,利用CSS作用域穿透特性控制插槽内容样式

<!-- 子组件 ChildComponent.vue -->
<template>
  <div class="child-wrapper">
    <div class="slot-container"> <!-- 定义插槽容器 -->
      <slot></slot>
    </div>
  </div>
</template>

<style scoped>
.slot-container :deep(div) { /* 穿透父组件插槽内容 */
  color: red;
  padding: 12px;
}
</style>

二、作用域插槽传递参数
通过‌作用域插槽‌将class参数传递给父组件,父组件动态绑定插槽元素的class

<!-- 子组件 ChildComponent.vue -->
<template>
  <slot :slotClass="'custom-class'"></slot> <!-- 传递class参数 -->
</template>

<!-- 父组件 ParentComponent.vue -->
<child-component>
  <template #default="{ slotClass }">
    <div :class="slotClass"> <!-- 动态绑定接收的class -->
      插槽内容
    </div>
  </template>
</child-component>

方案对比
选择方案时,若需‌完全由子组件控制样式‌,优先使用包裹层穿透方案;若需‌保留父组件样式调整灵活性‌,则采用作用域插槽传递参数。

3、具体实现方案

1)给插槽外面包装一个div
2)通过动态计算来设置slot外面div的class名字
3)不同的class里面通过deep选择到父组件可能用到的span和a并控制颜色

4、具体代码

<!--代码片段-->
<template v-if="$slots.edit || $slots.view || $slots.publish">
    <div :class="classStatusColor">
      <slot v-if="!!$slots.edit" name="edit" :model="modelEdit"></slot>
    </div>
<template>
  const statusColor = ref(getStatusColor());
  const classStatusColor = computed(() => ({
    'slot-edit-container-draft': statusColor.value === STATUS_DRAFT,
    'slot-edit-container-waiting-approve': statusColor.value === STATUS_WAITING_APPROVE,
    'slot-edit-container-reject': statusColor.value === STATUS_REJECT,
    'slot-edit-container-publish': statusColor.value === STATUS_PUBLISH,
  }));

// 代码片段按照优先级设置颜色STATUS_REJECT > STATUS_DRAFT > STATUS_WAITING_APPROVE > STATUS_WAITING_APPROVE > STATUS_PUBLISH
function getStatusColor() {
    let values: DataValue[];
    //values = ............//自己处理逻辑

    // 空值处理
    if (values === undefined) {
      return STATUS_UNKNOWN;
    }
    let statusList: number[] = [];
    for (let i of values) {
      if (i.value.status === undefined) {
        statusList.push(STATUS_UNKNOWN);
      } else {
        statusList.push(i.value.status);
      }
    }

    if (statusList.includes(STATUS_REJECT)) {
      return STATUS_REJECT;
    }
    if (statusList.includes(STATUS_DRAFT)) {
      return STATUS_DRAFT;
    }
    if (statusList.includes(STATUS_WAITING_APPROVE)) {
      return STATUS_WAITING_APPROVE;
    }
    if (statusList.includes(STATUS_PUBLISH)) {
      return STATUS_PUBLISH;
    }
    return STATUS_UNKNOWN;
  }

<style lang="less" scoped>
  // 红色是草稿状态
  .slot-edit-container-draft :deep(a) {
    color: rgb(238 102 102);
  }

  // 蓝色是待审核状态
  .slot-edit-container-waiting-approve :deep(a) {
    color: rgb(84 112 198);
  }

  // 橙色是驳回状态
  .slot-edit-container-reject :deep(a) {
    color: rgb(250 200 88);
  }

  // 黑色是已发布状态
  .slot-edit-container-publish :deep(a) {
    font-weight: black;
  }
</style>