前端组件选择决策指南

前端组件选择决策指南

专为AI辅助开发和前端开发者设计的组件选择系统性框架,解决”什么时候用Element Plus组件?什么时候用Storybook里的图标?“的核心问题


📋 指南使用说明

核心价值:本指南提供明确的决策规则,帮助你在开发前端画面时:

  1. 快速决策:根据UI需求选择正确的组件层次(atoms/molecules/organisms)
  2. 避免错误:明确Element Plus组件的使用边界,防止架构违规
  3. 高效复用:最大化利用现有Storybook组件库,减少重复造轮子
  4. AI协作优化:为AI提供清晰的组件选择逻辑,生成符合标准的代码

目标用户

  • AI开发工具:GitHub Copilot、Claude等,根据本指南生成合规组件代码
  • 前端开发者:新成员快速掌握组件使用规则,老成员统一设计决策
  • 设计系统维护者:确保组件使用的一致性和可维护性

使用场景

  1. 开发新页面时:按本指南选择组件层次和具体实现
  2. 创建新组件时:判断是否需要创建新组件,还是复用现有组件
  3. 代码审查时:验证组件使用是否符合项目标准
  4. AI提示词设计时:基于本指南构建更精准的组件生成指令

🏗️ 组件选择核心原则

1. Atomic Design层次原则

根据组件复杂度和复用范围,严格遵守五层结构:

层次职责范围创建条件技术特点
Atoms最小UI单元Element Plus组件包装使用设计令牌,无业务逻辑
Molecules小功能组合3次以上复用组合atoms,简单交互
Organisms复杂UI部件跨页面复用包含状态管理、验证逻辑
Templates页面布局3种以上页面共用定义结构,无具体内容
Domains业务领域组件特定业务场景封装完整业务功能

2. 3次规则(重用性判断)

  • 使用1-2次:内联实现,不创建独立组件
  • 使用3次以上:创建可复用组件
  • 跨项目复用:考虑提取到共享组件库

3. 设计令牌优先原则

  • 禁止硬编码:颜色、间距、字体大小必须使用CSS自定义属性
  • 语义化令牌:优先使用--ui-primary而非--color-red-500
  • 主题支持:所有组件必须支持亮/暗主题切换

4. Element Plus包装原则

  • 禁止直接使用<el-button><el-input>等原生Element Plus组件标签
  • 必须通过atoms:使用<tao-button><tao-input>等包装后的组件
  • 例外情况:仅在atoms组件内部实现中使用Element Plus组件

🔍 组件层次选择决策树

第一步:判断UI复杂度

"这是一个单一的可交互元素吗?"
├── 是 → 进入Atoms选择流程
└── 否 → "这是多个相关元素的组合吗?"
    ├── 是 → 进入Molecules选择流程  
    └── 否 → "这是一个完整的页面部分吗?"
        ├── 是 → 进入Organisms选择流程
        └── 否 → "这是一个页面布局框架吗?"
            ├── 是 → 进入Templates选择流程
            └── 否 → 进入Domains选择流程

第二步:各层次具体选择指南

Atoms(原子组件)选择条件

使用时机

  1. 单一UI元素:按钮、输入框、选择器、标签、图标占位符
  2. 需要基础交互:点击、聚焦、悬停
  3. 必须使用设计令牌进行样式定制
  4. 包装Element Plus原生组件

决策检查表

  • 是否是UI最小不可分割单元?
  • 是否能在不同上下文中独立使用?
  • 是否需要包装Element Plus组件?
  • 是否使用CSS自定义属性而非硬编码样式?

示例决策

需求:一个带主要样式的按钮
决策:使用<tao-button variant="primary">
原因:Button是基础UI单元,需要包装Element Plus的el-button

需求:一个文本输入框
决策:使用<tao-input type="text" placeholder="请输入">
原因:Input是基础UI单元,需要包装Element Plus的el-input

Molecules(分子组件)选择条件

使用时机

  1. 多个atoms的逻辑组合:带标签的输入框、搜索框、表单行
  2. 实现特定交互模式:输入+按钮组合
  3. 在同一页面内重复使用3次以上
  4. 包含简单的验证或状态逻辑

决策检查表

  • 是否由2个以上atoms组成?
  • 是否实现特定交互模式?
  • 是否在同一页面内使用3次以上?
  • 是否包含简单业务逻辑?

示例决策

需求:带标签和验证提示的输入框
决策:使用<tao-labeled-input label="邮箱" rules="email">
原因:由Label+Input+ErrorMessage组成,是常见表单模式

需求:搜索框(输入框+搜索按钮)
决策:使用<tao-search-box placeholder="搜索...">
原因:由Input+Button组成,是标准搜索交互模式

Organisms(有机体组件)选择条件

使用时机

  1. 复杂UI部件:完整表单、数据表格、卡片组件
  2. 跨多个页面复用
  3. 包含完整的状态管理和API交互
  4. 可能包含多个molecules和atoms

决策检查表

  • 是否是独立的功能模块?
  • 是否在多个页面中使用?
  • 是否需要管理复杂状态?
  • 是否需要API数据交互?

示例决策

需求:用户信息编辑表单(包含多个字段、提交逻辑)
决策:创建<tao-user-form :user="userData">
原因:包含多个表单字段、验证规则、提交逻辑,可跨页面复用

需求:产品列表表格(排序、分页、筛选)
决策:使用<tao-product-table :products="list">
原因:复杂交互组件,包含表格、分页、排序功能

Templates(模板组件)选择条件

使用时机

  1. 页面布局框架:定义页面结构区域
  2. 在3种以上不同页面类型中使用
  3. 不包含具体业务内容,只定义占位区域
  4. 支持插槽(slot)机制

示例

需求:管理后台布局(头部导航+侧边栏+主内容区)
决策:使用<tao-admin-layout>
├── <template #header>...</template>
├── <template #sidebar>...</template>
└── <template #default>...</template>

Domains(领域组件)选择条件

使用时机

  1. 特定业务场景的完整解决方案
  2. 封装复杂业务逻辑和多个organisms
  3. 通常在单一业务模块内使用
  4. 可能包含领域特定的状态管理

示例

需求:预约管理模块(日历视图+预约列表+表单)
决策:创建<tao-reservation-manager>
原因:封装完整的预约业务逻辑,包含多个UI组件和状态

🎨 Element Plus组件使用规则

核心规则:必须通过Atoms包装

<!-- ❌ 禁止:直接使用Element Plus组件 -->
<template>
  <el-button type="primary">提交</el-button>
  <el-input v-model="text" placeholder="请输入" />
</template>

<!-- ✅ 正确:使用包装后的Tao组件 -->
<template>
  <tao-button variant="primary">提交</tao-button>
  <tao-input v-model="text" placeholder="请输入" />
</template>

Atoms内部实现示例

<!-- frontend/src/components/atoms/button.vue -->
<script setup lang="ts">
import { ElButton } from 'element-plus'
import type { ButtonProps } from 'element-plus'

defineProps<ButtonProps & {
  variant?: 'primary' | 'outline' | 'tertiary' | 'ghost'
}>()
</script>

<template>
  <ElButton
    :type="variant === 'primary' ? 'primary' : 'default'"
    :class="`tao-button tao-button--${variant}`"
  >
    <slot />
  </ElButton>
</template>

<style scoped>
.tao-button {
  color: var(--ui-primary);
  background-color: var(--ui-surface);
  border: 1px solid var(--ui-border);
}
</style>

可用的包装组件清单

根据Storybook文档,已有以下包装组件:

基础Atoms(必须使用这些包装版本)

Element Plus原生Tao包装组件关键属性
<el-button><tao-button>variant, size, shape, disabled
<el-input><tao-input>type, placeholder, disabled, readonly
<el-select><tao-select>options, multiple, filterable
<el-checkbox><tao-checkbox>label, checked, disabled
<el-radio><tao-radio>label, value, disabled
<el-date-picker><tao-date-picker>type, format, value-format
<el-dialog><tao-dialog>visible, title, width
<el-table><tao-table>data, columns, stripe

组合Molecules(直接使用这些组件)

组件名称用途构成
<tao-labeled-input>带标签的输入框Label + Input + ErrorMessage
<tao-form-group>表单组多个LabeledInput + 布局
<tao-search-box>搜索框Input + Button
<tao-pagination>分页组件多个Button + 输入框
<tao-date-range>日期范围选择器2个DatePicker + 逻辑

例外情况:何时可以在Atoms内部使用Element Plus

  1. Atoms组件实现内部button.vue内部使用<ElButton>
  2. Storybook文档定义.stories.ts文件中展示组件API
  3. 测试代码中:单元测试中直接引用Element Plus组件进行测试

🔤 图标组件选择指南

图标来源规则

"图标从哪里获取?"
├── **项目自定义图标** → 使用 assets/icons/ 中的组件
├── **Element Plus图标** → 通过atoms包装后使用  
└── **第三方图标库** → 禁止使用(FontAwesome等仅限现有代码)

1. 使用项目自定义图标组件

位置frontend/src/assets/icons/*.vue 命名规则Icon前缀 + PascalCase(IconSearch.vue使用方法

<!-- ✅ 正确:直接使用自定义图标组件 -->
<template>
  <icon-search />
  <icon-arrow-down />
  <icon-close />
</template>

<script setup lang="ts">
// 无需导入,Nuxt自动导入(根据 nuxt.config.ts 配置)
</script>

可用图标清单(根据Storybook):

  • 基础操作:icon-add, icon-remove, icon-close, icon-search
  • 方向箭头:icon-arrow-up, icon-arrow-down, icon-arrow-left, icon-arrow-right
  • 状态指示:icon-exclamation-triangle, icon-light-bulb, icon-select
  • 文件操作:icon-download, icon-upload, icon-paperclip
  • 界面控制:icon-window-maximize, icon-window-restore
  • 更多详见:frontend/src/assets/icons/ 目录

2. Element Plus图标的正确用法

错误模式

<!-- ❌ 禁止:直接使用Element Plus图标 -->
<template>
  <el-icon><search /></el-icon>
</template>

<script setup lang="ts">
import { Search } from '@element-plus/icons-vue'
</script>

正确模式

<!-- ✅ 正确:通过自定义图标组件或atoms包装 -->
<template>
  <!-- 方式1:使用项目自定义图标 -->
  <icon-search />
  
  <!-- 方式2:通过atoms组件间接使用 -->
  <tao-button :icon-left="SearchIcon">搜索</tao-button>
</template>

<script setup lang="ts">
// 如果需要,在atoms组件内部处理Element Plus图标
import { Search } from '@element-plus/icons-vue'
const SearchIcon = Search
</script>

3. 图标使用决策矩阵

使用场景推荐方案示例
独立图标显示项目自定义图标组件<icon-search />
按钮内图标Tao按钮的icon-left/right属性<tao-button :icon-left="IconSearch">
表单前缀/后缀图标Tao输入框的prefix-icon/suffix-icon<tao-input prefix-icon="User">
动态图标切换通过组件动态渲染<component :is="currentIcon" />

4. 图标样式规范

/* ✅ 正确:使用设计令牌控制图标样式 */
.icon {
  color: var(--ui-icon);
  width: var(--icon-size-md);
  height: var(--icon-size-md);
}

/* ❌ 禁止:硬编码图标样式 */
.icon {
  color: #666; /* 错误 */
  width: 24px; /* 错误 */
}

🤖 AI辅助组件选择工具

1. 专用Chatmode:Nuxt3前端工程专家

文件.github/chatmodes/1-expert-nuxt3-frontend-engineer.chatmode.md 作用:提供Nuxt3 + TypeScript前端工程专家指导,确保AI理解项目架构

关键指令

  • 强调SPA模式(非SSR/SSG)
  • 使用Composition API和TypeScript严格模式
  • 遵循Atomic Design目录结构
  • 必须使用设计令牌和包装组件

2. Atomic Component提示词

文件.github/prompts/atomic-component.prompt.md 用途:生成符合Atomic Design规范的组件

使用格式

/atomic-component componentName=button layer=atoms baseComponent=el-button props='{"variant":"primary","size":"medium"}' apply=true

参数说明

  • componentName: 组件名称(小写)
  • layer: 组件层次(atoms/molecules/organisms/templates/domains)
  • baseComponent: 基础Element Plus组件(仅atoms需要)
  • props: 组件属性定义(JSON格式)
  • apply: 是否直接生成代码

3. Mock Screen提示词

文件.github/prompts/mock-screen.prompt.md 用途:从线框图生成页面模板

使用格式

/mock-screen screenName=login screenType=form apply=true

前提条件:用户已在聊天中上传线框图图片

4. 组件选择决策支持流程

AI辅助决策步骤

  1. 需求解析:AI分析用户提供的设计文档摘要
  2. 组件匹配:检查Storybook中是否有现有组件
  3. 层次判断:根据复杂度确定组件层次
  4. 生成建议:提供组件选择方案和代码示例

用户输入示例

需求:用户登录页面
- 邮箱输入框(必填,邮箱格式验证)
- 密码输入框(必填,密码格式验证)  
- 登录按钮(主要样式)
- "忘记密码"链接

AI输出示例

组件选择方案:
1. 使用 <tao-input> 作为邮箱和密码输入框
2. 使用 <tao-button variant="primary"> 作为登录按钮
3. 使用 <tao-link> 作为忘记密码链接
4. 使用 <tao-form> 包装整个表单,添加验证规则

生成代码:...

📋 组件创建决策检查清单

决策流程检查点

检查点1:是否已有现成组件?

  • 检查Storybook组件库(frontend/src/components/
  • 搜索类似功能的现有组件
  • 确认组件API是否满足需求
  • 考虑通过Props扩展而非创建新组件

检查点2:是否符合创建条件?

  • 3次规则:是否会在3个以上地方使用?
  • 层次合适:是否属于正确的Atomic Design层次?
  • 复杂度:是否足够复杂需要独立组件?
  • 复用性:是否有明确的复用场景?

检查点3:技术实现是否正确?

  • 设计令牌:是否使用CSS自定义属性?
  • Element Plus包装:是否通过atoms包装?(如需要)
  • 类型安全:是否提供完整的TypeScript类型?
  • 国际化:是否支持i18n?(如有文本内容)
  • 可访问性:是否包含ARIA属性?

组件创建批准矩阵

条件创建组件内联实现备注
使用次数 ≥ 3✅ 推荐❌ 不推荐满足重用性条件
使用次数 = 2⚠️ 可考虑⚠️ 可考虑根据复杂度决定
使用次数 = 1❌ 不推荐✅ 推荐避免过度组件化
跨页面复用✅ 推荐❌ 不推荐提高一致性
包含复杂交互✅ 推荐❌ 不推荐封装复杂性
简单UI组合⚠️ 可考虑⚠️ 可考虑根据团队约定

🚨 常见错误及纠正示例

错误1:直接使用Element Plus组件

<!-- ❌ 错误代码 -->
<template>
  <el-button type="primary">提交</el-button>
</template>

<!-- ✅ 纠正代码 -->
<template>
  <tao-button variant="primary">提交</tao-button>
</template>

错误2:硬编码图标组件

<!-- ❌ 错误代码 -->
<template>
  <el-icon><search /></el-icon>
</template>

<script setup lang="ts">
import { Search } from '@element-plus/icons-vue'
</script>

<!-- ✅ 纠正代码 -->
<template>
  <icon-search />
</template>
<!-- 或使用带图标的按钮 -->
<template>
  <tao-button :icon-left="IconSearch">搜索</tao-button>
</template>

错误3:不正确的组件层次

<!-- ❌ 错误:在atoms中实现复杂逻辑 -->
<!-- atoms/复杂表单.vue (错误位置) -->

<!-- ✅ 正确:创建organisms组件 -->
<!-- organisms/用户表单.vue -->

错误4:忽略设计令牌

<!-- ❌ 错误:硬编码样式 -->
<style scoped>
.button {
  color: #ff0000; /* 错误:硬编码颜色 */
  padding: 10px;  /* 错误:硬编码间距 */
}
</style>

<!-- ✅ 正确:使用设计令牌 -->
<style scoped>
.button {
  color: var(--ui-primary);
  padding: var(--spacing-2);
}
</style>

🔗 相关文档参考

核心标准文档

  1. 前端实现标准docs/guidelines/implementation/frontend.md

    • Atomic Design目录结构定义
    • API调用和状态管理规范
  2. 组件设计指南docs/guidelines/design/11_frontend-component-design-guidelines.md

    • 组件层次职责划分
    • 3次规则详细说明
  3. 命名规范指南docs/guidelines/design/10_naming-conventions-guidelines.md

    • 文件、组件、变量命名规则

AI配置文档

  1. Copilot基础指令.github/copilot-instructions.md

    • AI行为准则和安全原则
  2. 组件生成提示词.github/prompts/atomic-component.prompt.md

    • 标准化组件生成指令

实现教程文档

  1. 表单验证教程frontend/docs/guides/validation.md

    • 基于Zod的验证实现
  2. 国际化教程frontend/docs/guides/i18n.md

    • Vue I18n配置和使用

设计系统资源

  1. Storybook组件库npm run storybook(本地访问)

    • 所有可用组件的交互式文档
  2. 设计令牌定义frontend/src/assets/styles/tokens.css

    • CSS自定义属性定义

📞 支持与升级

文档更新机制

  • 版本控制:本指南随项目架构演进定期更新
  • 变更记录:重大架构变更需同步更新本指南
  • 团队同步:更新后需通过团队评审并通知所有成员

问题反馈流程

  1. 发现不一致:记录具体场景和期望行为
  2. 检查文档:确认是否文档缺失或错误
  3. 提交修正:通过PR更新相关文档
  4. 团队通知:变更后同步所有相关方

AI提示词优化

  • 使用反馈:记录AI生成代码的质量问题
  • 提示词迭代:根据反馈优化.github/prompts/中的指令
  • 测试验证:更新后测试AI生成效果

版本历史

  • v1.0 (2026-02-04): 初始版本,基于APJ-B2B项目现状创建
  • 维护者: APJ-B2B前端开发团队
  • 目标版本: Nuxt 3 + Vue 3 + Element Plus + TypeScript

🎯 快速决策速查卡

场景1:需要一个按钮

决策:使用 <tao-button>
属性:variant="primary|outline|tertiary|ghost"
示例:<tao-button variant="primary">提交</tao-button>

场景2:需要一个输入框

决策:使用 <tao-input>
属性:type="text|password|email"
示例:<tao-input v-model="email" placeholder="邮箱" />

场景3:需要一个图标

决策:使用 <icon-xxx>
来源:assets/icons/ 目录
示例:<icon-search /> <icon-close />

场景4:需要表单验证

决策:使用 <tao-form> + <tao-form-item>
规则:utils/validation-rules.ts
示例:<tao-form :rules="rules">

场景5:需要复杂交互组件

决策:创建 organisms/xxx.vue
构成:组合多个molecules和atoms
示例:organisms/user-form.vue

核心要点:组件选择不是艺术,而是工程决策。遵循本指南的规则和检查点,确保代码的一致性、可维护性和可扩展性。当有疑问时,优先复用现有组件,避免过度设计。

最后更新: 2026-02-04
适用版本: APJ-B2B前端项目 v1.0+
相关标准: Atomic Design、Element Plus包装规范、设计令牌系统