跳转至

业务组件接入指南

📄 创建: 未记录

https://doc.xpku.com/raw/tech/frontend/theme/ui-spec.md

本文档说明如何在业务组件中正确消费主题模块提供的颜色变量。

核心原则

业务组件只消费颜色变量,不直接操作主题状态。

主题模块提供了完整的 CSS 变量系统,业务组件只需通过 var(--bams-*) 的方式引用这些变量即可。

全局颜色变量列表

主品牌色及其交互态

--bams-primary                /* 主品牌色 */
--bams-primary-hover          /* 主品牌色(悬停态) */
--bams-primary-active         /* 主品牌色(激活态) */
--bams-primary-border         /* 主品牌色(边框态) */
--bams-primary-text           /* 主品牌色(文本态) */
--bams-primary-soft           /* 主品牌色(弱化态) */
--bams-primary-bg             /* 主品牌色(背景态) */
--bams-primary-bg-hover       /* 主品牌色(背景悬停态) */
--bams-primary-outline        /* 主品牌色(轮廓态) */

链接与信息态

--bams-link-color             /* 链接色 */
--bams-link-hover             /* 链接色(悬停态) */
--bams-link-active            /* 链接色(激活态) */
--bams-info-color             /* 信息提示色 */
--bams-info-text              /* 信息提示色(文本态) */
--bams-info-border            /* 信息提示色(边框态) */
--bams-info-bg                /* 信息提示色(背景态) */
--bams-info-soft              /* 信息提示色(弱化态) */

语义状态色

/* 成功 */
--bams-success-color          /* 成功态颜色 */
--bams-success-text           /* 成功态文本色 */
--bams-success-border         /* 成功态边框色 */
--bams-success-bg             /* 成功态背景色 */
--bams-success-soft           /* 成功态弱化色 */

/* 警告 */
--bams-warning-color          /* 警告态颜色 */
--bams-warning-text           /* 警告态文本色 */
--bams-warning-border         /* 警告态边框色 */
--bams-warning-bg             /* 警告态背景色 */
--bams-warning-soft           /* 警告态弱化色 */

/* 错误 */
--bams-error-color            /* 错误态颜色 */
--bams-error-text             /* 错误态文本色 */
--bams-error-border           /* 错误态边框色 */
--bams-error-bg               /* 错误态背景色 */
--bams-error-soft             /* 错误态弱化色 */

页面与容器背景层级

--bams-page-bg                /* 页面背景色 */
--bams-layout-bg              /* 布局背景色 */
--bams-surface-bg             /* 表面背景色 */
--bams-surface-bg-elevated    /* 表面背景色(抬升态) */
--bams-surface-bg-muted       /* 表面背景色(弱化态) */
--bams-content-bg             /* 内容区背景色 */
--bams-toolbar-bg             /* 工具栏背景色 */
--bams-sider-bg               /* 侧边栏背景色 */
--bams-menu-bg                /* 菜单背景色 */

菜单态

--bams-menu-text              /* 菜单文本色 */
--bams-menu-selected-bg       /* 菜单选中态背景色 */
--bams-menu-selected-text     /* 菜单选中态文本色 */
--bams-menu-hover-bg          /* 菜单悬停态背景色 */

文本层级

--bams-text-color             /* 主文本色 */
--bams-text-secondary         /* 次要文本色 */
--bams-text-tertiary          /* 三级文本色 */
--bams-text-quaternary        /* 四级文本色 */
--bams-text-disabled          /* 禁用态文本色 */
--bams-text-placeholder       /* 占位符文本色 */
--bams-text-inverse           /* 反白文本色 */

边框层级

--bams-border-color           /* 主边框色 */
--bams-border-secondary       /* 次要边框色 */
--bams-border-strong          /* 强边框色 */
--bams-divider-color          /* 分割线色 */

头部与图标

--bams-header-bg              /* 头部背景色 */
--bams-header-text            /* 头部文本色 */
--bams-icon-color             /* 图标色 */
--bams-icon-secondary         /* 次要图标色 */

通用交互态

--bams-hover-bg               /* 悬停态背景色 */
--bams-active-bg              /* 激活态背景色 */
--bams-selected-bg            /* 选中态背景色 */
--bams-disabled-bg            /* 禁用态背景色 */
--bams-disabled-border        /* 禁用态边框色 */

滚动条与阴影

--bams-scrollbar-thumb        /* 滚动条滑块色 */
--bams-scrollbar-track        /* 滚动条轨道色 */
--bams-shadow-header          /* 头部阴影 */
--bams-shadow-card            /* 卡片阴影 */
--bams-shadow-overlay         /* 浮层阴影 */

遮罩与焦点态

--bams-mask-bg                /* 遮罩背景色 */
--bams-focus-ring             /* 焦点环 */

浮层与弹出层

--bams-overlay-bg             /* 浮层背景色 */
--bams-popover-bg             /* 气泡卡片背景色 */
--bams-dropdown-bg            /* 下拉菜单背景色 */
--bams-tooltip-bg             /* 工具提示背景色 */
--bams-tooltip-text           /* 工具提示文本色 */

表单与输入控件

--bams-input-bg               /* 输入框背景色 */
--bams-input-bg-hover         /* 输入框悬停态背景色 */
--bams-input-bg-disabled      /* 输入框禁用态背景色 */
--bams-input-text             /* 输入框文本色 */
--bams-input-placeholder      /* 输入框占位符文本色 */
--bams-input-border           /* 输入框边框色 */
--bams-input-border-hover     /* 输入框悬停态边框色 */
--bams-input-border-focus     /* 输入框聚焦态边框色 */
--bams-input-border-error     /* 输入框错误态边框色 */
--bams-input-border-warning   /* 输入框警告态边框色 */
--bams-input-shadow-focus     /* 输入框聚焦态阴影 */

按钮

--bams-button-default-bg      /* 默认按钮背景色 */
--bams-button-default-text    /* 默认按钮文本色 */
--bams-button-default-border  /* 默认按钮边框色 */
--bams-button-default-hover-bg /* 默认按钮悬停态背景色 */
--bams-button-primary-bg      /* 主要按钮背景色 */
--bams-button-primary-text    /* 主要按钮文本色 */
--bams-button-primary-hover-bg /* 主要按钮悬停态背景色 */
--bams-button-primary-active-bg /* 主要按钮激活态背景色 */

表格与列表

--bams-table-bg               /* 表格背景色 */
--bams-table-header-bg        /* 表格表头背景色 */
--bams-table-header-text      /* 表格表头文本色 */
--bams-table-border           /* 表格边框色 */
--bams-table-row-hover-bg     /* 表格行悬停态背景色 */
--bams-table-row-selected-bg  /* 表格行选中态背景色 */
--bams-table-row-striped-bg   /* 表格斑马纹背景色 */

标签与徽标

--bams-tag-default-bg         /* 默认标签背景色 */
--bams-tag-default-text       /* 默认标签文本色 */
--bams-tag-default-border     /* 默认标签边框色 */

在业务组件中使用全局变量

基本用法

在组件的 <style> 标签中直接使用 var(--bams-*) 引用变量:

<template>
  <div class="business-card">
    <div class="card-title">标题</div>
    <div class="card-content">内容</div>
  </div>
</template>

<style scoped lang="less">
  .business-card {
    background: var(--bams-surface-bg);
    border: 1px solid var(--bams-border-color);
    border-radius: 8px;
    padding: 16px;
    box-shadow: var(--bams-shadow-card);

    .card-title {
      color: var(--bams-text-color);
      font-size: 16px;
      font-weight: 500;
      margin-bottom: 8px;
    }

    .card-content {
      color: var(--bams-text-secondary);
      font-size: 14px;
    }
  }
</style>

按钮样式示例

<style scoped lang="less">
  .business-button {
    background: var(--bams-button-primary-bg);
    color: var(--bams-button-primary-text);
    border: none;
    border-radius: 6px;
    padding: 8px 16px;
    cursor: pointer;
    transition: background 0.2s;

    &:hover {
      background: var(--bams-primary-hover);
    }

    &:active {
      background: var(--bams-primary-active);
    }
  }
</style>

局部主题颜色变量的应用

需求背景

在实际业务开发中,有些组件需要相对独立的主题表现,不能完全受全局主题控制,典型场景包括:

  • 第三方组件集成:需要为外部引入的组件适配项目主题,但又不想影响全局样式
  • 特殊业务区域:如仪表盘、营销页面等需要独立配色以突出视觉效果
  • 组件定制化:某些业务组件有特定的设计规范,需要独立的颜色体系
  • 暗色模式适配:组件自身需要独立的暗色模式处理逻辑

此时可以使用局部主题方案,在不影响全局主题的前提下,为特定组件或区域提供独立的主题变量。

当业务组件需要独立的主题变量(不受全局主题影响)时,有以下几种方法:

局部主题定义规范

使用局部主题时必须遵循此规范。

使用局部主题时,必须将配置抽取到单独的文件中。

必须的文件结构:

src/
├── theme/                    # 必须放在此目录
│   ├── xxxTheme.js           # 必须使用此命名规范
│   └── yyyTheme.js
└── business/
    └── components/
        └── XxxComponent.vue  # 导入主题配置

配置文件示例:

// src/theme/xxxTheme.js
export const THEME_MODE_VARS = {
  light: {
    "--component-bg": "#ffffff",
    "--component-text": "#1e293b",
    colorScheme: "light",
  },
  dark: {
    "--component-bg": "#1e293b",
    "--component-text": "#f1f5f9",
    colorScheme: "dark",
  },
};

export const THEME_PRESET_VARS = {
  "material.blue": {
    "--component-primary": "#0d6cbd",
  },
};

组件中使用:

<script setup>
  import { LocalThemeContainer } from "@bams-app/theme";
  import { THEME_MODE_VARS, THEME_PRESET_VARS } from "../../theme/xxxTheme";
</script>

方法一:使用 ComponentContainer 或 PageWorkContainer 组件(最推荐)

对于业务组件的根容器,推荐使用 ComponentContainerPageWorkContainer 组件,它们已经内置了主题变量处理功能。

Props 定义

参数 说明 类型 默认值
containerStyle 容器自定义样式 Object {}
themeModeVars 主题模式变量配置 Object undefined
themePresetVars 主题预设变量配置 Object undefined

使用示例

1. 首先创建主题配置文件

// src/theme/businessComponentTheme.js
export const THEME_MODE_VARS = {
  light: {
    "--bams-page-bg": "#eef3f8",
    "--bams-surface-bg": "#ffffff",
    "--bams-text-color": "#223548",
    "--bams-text-secondary": "#6b7c8f",
    "--bams-border-color": "#e7ebee",
    colorScheme: "light",
  },
  dark: {
    "--bams-page-bg": "#0b1220",
    "--bams-surface-bg": "#111827",
    "--bams-text-color": "#e5edf7",
    "--bams-text-secondary": "#94a3b8",
    "--bams-border-color": "#253246",
    colorScheme: "dark",
  },
};

export const THEME_PRESET_VARS = {
  "material.blue": {
    "--bams-primary": "#0d6cbd",
    "--bams-primary-soft": "color-mix(in srgb, #0d6cbd 12%, transparent)",
  },
  "material.teal": {
    "--bams-primary": "#13c2c2",
    "--bams-primary-soft": "color-mix(in srgb, #13c2c2 12%, transparent)",
  },
};

2. 在组件中使用

<template>
  <ComponentContainer :theme-mode-vars="THEME_MODE_VARS" :theme-preset-vars="THEME_PRESET_VARS">
    <div class="title">业务组件标题</div>
    <div class="content">业务组件内容</div>
  </ComponentContainer>
</template>

<script setup>
  import { ComponentContainer } from "@bams-app/components";
  import { THEME_MODE_VARS, THEME_PRESET_VARS } from "../../theme/businessComponentTheme";
</script>

<style scoped lang="less">
  .title {
    color: var(--bams-text-color);
    font-size: 16px;
    font-weight: 500;
  }

  .content {
    color: var(--bams-text-secondary);
    font-size: 14px;
  }
</style>

方法二:使用 LocalThemeContainer 组件

对于需要快速注入局部主题变量的场景,推荐使用 LocalThemeContainer 组件,它会自动处理变量计算和样式合并,并提供主题状态暴露。

Props 定义

参数 说明 类型 默认值
containerStyle 容器自定义样式 Object {}
themeModeVars 主题模式变量配置 Object undefined
themePresetVars 主题预设变量配置 Object undefined

Events 定义

事件名 说明 回调参数
theme-change 主题变化时触发 themeStore.$state

插槽暴露属性

属性 说明
mode 当前主题模式(light/dark)
preset 当前主题预设
resolvedMode 解析后的模式(考虑系统默认)
modeClass 模式对应的 CSS 类名
presetClass 预设对应的 CSS 类名
localThemeVars 生成的局部变量对象
mergedStyle 合并后的最终样式对象(含 containerStyle)

使用示例

1. 首先创建主题配置文件

// src/theme/localThemeComponentTheme.js
export const THEME_MODE_VARS = {
  light: {
    "--bams-page-bg": "#eef3f8",
    "--bams-surface-bg": "#ffffff",
    "--bams-text-color": "#223548",
    "--bams-text-secondary": "#6b7c8f",
    "--bams-border-color": "#e7ebee",
    colorScheme: "light",
  },
  dark: {
    "--bams-page-bg": "#0b1220",
    "--bams-surface-bg": "#111827",
    "--bams-text-color": "#e5edf7",
    "--bams-text-secondary": "#94a3b8",
    "--bams-border-color": "#253246",
    colorScheme: "dark",
  },
};

export const THEME_PRESET_VARS = {
  "material.blue": {
    "--bams-primary": "#0d6cbd",
    "--bams-primary-soft": "color-mix(in srgb, #0d6cbd 12%, transparent)",
  },
  "material.teal": {
    "--bams-primary": "#13c2c2",
    "--bams-primary-soft": "color-mix(in srgb, #13c2c2 12%, transparent)",
  },
};

2. 在组件中使用

<template>
  <LocalThemeContainer :theme-mode-vars="THEME_MODE_VARS" :theme-preset-vars="THEME_PRESET_VARS" @theme-change="handleThemeChange" v-slot="slotState">
    <div class="title">业务组件标题</div>
    <div class="content">业务组件内容</div>
    <div class="info">当前模式:{{ slotState.mode }}</div>
  </LocalThemeContainer>
</template>

<script setup>
  import { LocalThemeContainer } from "@bams-app/theme";
  import { THEME_MODE_VARS, THEME_PRESET_VARS } from "../../theme/localThemeComponentTheme";

  const handleThemeChange = themeState => {
    console.log("主题变化", themeState);
  };
</script>

<style scoped lang="less">
  .title {
    color: var(--bams-text-color);
    font-size: 16px;
    font-weight: 500;
  }

  .content {
    color: var(--bams-text-secondary);
    font-size: 14px;
  }

  .info {
    margin-top: 16px;
    color: var(--bams-primary);
  }
</style>

方法三:使用 useLocalThemeVars 工具

1. 首先创建主题配置文件

// src/theme/customComponentTheme.js
export const THEME_MODE_VARS = {
  light: {
    "--bams-page-bg": "#eef3f8",
    "--bams-surface-bg": "#ffffff",
    "--bams-text-color": "#223548",
    "--bams-text-secondary": "#6b7c8f",
    "--bams-border-color": "#e7ebee",
    colorScheme: "light",
  },
  dark: {
    "--bams-page-bg": "#0b1220",
    "--bams-surface-bg": "#111827",
    "--bams-text-color": "#e5edf7",
    "--bams-text-secondary": "#94a3b8",
    "--bams-border-color": "#253246",
    colorScheme: "dark",
  },
};

export const THEME_PRESET_VARS = {
  "material.blue": {
    "--bams-primary": "#0d6cbd",
    "--bams-primary-soft": "color-mix(in srgb, #0d6cbd 12%, transparent)",
  },
  "material.teal": {
    "--bams-primary": "#13c2c2",
    "--bams-primary-soft": "color-mix(in srgb, #13c2c2 12%, transparent)",
  },
};

2. 在组件中使用

<template>
  <div class="custom-component" :style="localThemeVars">
    <div class="title">自定义主题组件</div>
    <div class="content">使用局部变量</div>
  </div>
</template>

<script setup>
  import { useLocalThemeVars } from "@bams-app/theme";
  import { THEME_MODE_VARS, THEME_PRESET_VARS } from "../../theme/customComponentTheme";

  // 使用 useLocalThemeVars 获取计算后的局部变量
  const { localThemeVars } = useLocalThemeVars({
    themeModeVars: THEME_MODE_VARS,
    themePresetVars: THEME_PRESET_VARS,
  });
</script>

<style scoped lang="less">
  .custom-component {
    background: var(--bams-page-bg);
    color: var(--bams-text-color);
    border: 1px solid var(--bams-border-color);
    padding: 20px;
  }
</style>

方法四:手动管理局部变量

如果需要更灵活的控制,也可以手动实现局部变量:

1. 首先创建主题配置文件

// src/theme/manualTheme.js
export const THEME_MODE_VARS = {
  light: {
    "--custom-bg": "#ffffff",
    "--custom-text": "#223548",
    colorScheme: "light",
  },
  dark: {
    "--custom-bg": "#111827",
    "--custom-text": "#e5edf7",
    colorScheme: "dark",
  },
};

export const getCustomThemeVars = (mode, presetConfig) => {
  const currentMode = mode || "light";
  const modeVars = THEME_MODE_VARS[currentMode];
  return {
    ...modeVars,
    "--custom-primary": presetConfig?.primary || "#0d6cbd",
  };
};

2. 在组件中使用

<template>
  <div class="custom-wrapper" :style="localThemeVars">
    <!-- 组件内容 -->
  </div>
</template>

<script setup>
  import { computed } from "vue";
  import { getThemePreset, useThemeState } from "@bams-app/theme";
  import { THEME_MODE_VARS, getCustomThemeVars } from "../../theme/manualTheme";

  const { preset, resolvedMode } = useThemeState();

  const localThemeVars = computed(() => {
    const presetConfig = getThemePreset(preset.value);
    return getCustomThemeVars(resolvedMode.value, presetConfig);
  });
</script>

<style scoped lang="less">
  .custom-wrapper {
    background: var(--custom-bg);
    color: var(--custom-text);
  }
</style>

最佳实践

  1. 始终使用 var(--bams-*) 变量,不要直接写固定颜色值
  2. 优先使用语义化变量,如 --bams-text-color 而非 #333
  3. 避免过度自定义,尽量复用全局主题变量
  4. 局部变量仅在必要时使用,优先保持与全局主题一致
  5. 在弹出层组件中设置 getPopupContainer,确保弹出层继承局部变量
  6. 局部主题配置必须抽取到单独的 src/theme/ 目录文件中
  7. 主题配置文件命名规范:必须使用 xxxTheme.js 格式
<template>
  <div ref="containerRef" :style="localThemeVars">
    <a-popover :get-popup-container="getPopupContainer"> 内容 </a-popover>
  </div>
</template>

<script setup>
  import { ref } from "vue";

  const containerRef = ref(null);

  const getPopupContainer = () => {
    return containerRef.value || document.body;
  };
</script>

注意事项

  • 业务组件不应直接操作 useThemeStore,只通过 CSS 变量消费主题
  • 局部变量会覆盖同作用域内的同名全局变量
  • 如果没有启用主题功能(VUE_APP_ENABLE_THEME 未设置),将使用默认浅色主题变量

在 JavaScript 中获取 CSS 变量

除了在 CSS 中使用 var(--bams-*) 外,还可以在 JS 中动态获取这些变量。

API 概览

函数名 说明
getCssVar(varName, element?) 获取单个 CSS 变量的值
getCssVars(varNames, element?) 获取多个指定 CSS 变量的值
getAllCssVars(element?) 获取所有 --bams- 开头的 CSS 变量

基础用法

import { getCssVar, getCssVars, getAllCssVars } from "@bams-app/theme";

// 获取单个变量(支持两种写法)
const primary = getCssVar("--bams-primary");
const primary = getCssVar("primary"); // 自动补全前缀

// 获取多个变量
const vars = getCssVars(["primary", "text-color", "success-color"]);
console.log(vars.primary);
console.log(vars.textColor); // 自动转换为驼峰命名

// 获取所有变量
const allVars = getAllCssVars();

在 Vue 组件中响应式使用

<script setup>
  import { computed, watch } from "vue";
  import { getCssVar, getAllCssVars, useThemeState } from "@bams-app/theme";

  const { preset, resolvedMode } = useThemeState();

  // 响应式获取单个变量
  const primaryColor = computed(() => getCssVar("primary"));

  // 响应式获取所有变量
  const themeColors = computed(() => getAllCssVars());

  // 监听主题变化
  watch([preset, resolvedMode], () => {
    console.log("主题已更新");
  });
</script>

<template>
  <div>
    <p>当前主色: {{ primaryColor }}</p>
    <div
      :style="{
        color: themeColors.textColor,
        background: themeColors.pageBg,
      }"
    >
      主题内容
    </div>
  </div>
</template>

变量名映射

CSS 变量使用 kebab-case(如 --bams-text-color),在 JS 返回对象中会自动转换为 camelCase(如 textColor)。