前端组件选择决策指南
专为AI辅助开发和前端开发者设计的组件选择系统性框架,解决”什么时候用Element Plus组件?什么时候用Storybook里的图标?“的核心问题
📋 指南使用说明
核心价值:本指南提供明确的决策规则,帮助你在开发前端画面时:
- 快速决策:根据UI需求选择正确的组件层次(atoms/molecules/organisms)
- 避免错误:明确Element Plus组件的使用边界,防止架构违规
- 高效复用:最大化利用现有Storybook组件库,减少重复造轮子
- AI协作优化:为AI提供清晰的组件选择逻辑,生成符合标准的代码
目标用户:
- AI开发工具:GitHub Copilot、Claude等,根据本指南生成合规组件代码
- 前端开发者:新成员快速掌握组件使用规则,老成员统一设计决策
- 设计系统维护者:确保组件使用的一致性和可维护性
使用场景:
- 开发新页面时:按本指南选择组件层次和具体实现
- 创建新组件时:判断是否需要创建新组件,还是复用现有组件
- 代码审查时:验证组件使用是否符合项目标准
- 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(原子组件)选择条件
使用时机:
- 单一UI元素:按钮、输入框、选择器、标签、图标占位符
- 需要基础交互:点击、聚焦、悬停
- 必须使用设计令牌进行样式定制
- 包装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(分子组件)选择条件
使用时机:
- 多个atoms的逻辑组合:带标签的输入框、搜索框、表单行
- 实现特定交互模式:输入+按钮组合
- 在同一页面内重复使用3次以上
- 包含简单的验证或状态逻辑
决策检查表:
- 是否由2个以上atoms组成?
- 是否实现特定交互模式?
- 是否在同一页面内使用3次以上?
- 是否包含简单业务逻辑?
示例决策:
需求:带标签和验证提示的输入框
决策:使用<tao-labeled-input label="邮箱" rules="email">
原因:由Label+Input+ErrorMessage组成,是常见表单模式
需求:搜索框(输入框+搜索按钮)
决策:使用<tao-search-box placeholder="搜索...">
原因:由Input+Button组成,是标准搜索交互模式
Organisms(有机体组件)选择条件
使用时机:
- 复杂UI部件:完整表单、数据表格、卡片组件
- 跨多个页面复用
- 包含完整的状态管理和API交互
- 可能包含多个molecules和atoms
决策检查表:
- 是否是独立的功能模块?
- 是否在多个页面中使用?
- 是否需要管理复杂状态?
- 是否需要API数据交互?
示例决策:
需求:用户信息编辑表单(包含多个字段、提交逻辑)
决策:创建<tao-user-form :user="userData">
原因:包含多个表单字段、验证规则、提交逻辑,可跨页面复用
需求:产品列表表格(排序、分页、筛选)
决策:使用<tao-product-table :products="list">
原因:复杂交互组件,包含表格、分页、排序功能
Templates(模板组件)选择条件
使用时机:
- 页面布局框架:定义页面结构区域
- 在3种以上不同页面类型中使用
- 不包含具体业务内容,只定义占位区域
- 支持插槽(slot)机制
示例:
需求:管理后台布局(头部导航+侧边栏+主内容区)
决策:使用<tao-admin-layout>
├── <template #header>...</template>
├── <template #sidebar>...</template>
└── <template #default>...</template>
Domains(领域组件)选择条件
使用时机:
- 特定业务场景的完整解决方案
- 封装复杂业务逻辑和多个organisms
- 通常在单一业务模块内使用
- 可能包含领域特定的状态管理
示例:
需求:预约管理模块(日历视图+预约列表+表单)
决策:创建<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
- Atoms组件实现内部:
button.vue内部使用<ElButton> - Storybook文档定义:
.stories.ts文件中展示组件API - 测试代码中:单元测试中直接引用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辅助决策步骤:
- 需求解析:AI分析用户提供的设计文档摘要
- 组件匹配:检查Storybook中是否有现有组件
- 层次判断:根据复杂度确定组件层次
- 生成建议:提供组件选择方案和代码示例
用户输入示例:
需求:用户登录页面
- 邮箱输入框(必填,邮箱格式验证)
- 密码输入框(必填,密码格式验证)
- 登录按钮(主要样式)
- "忘记密码"链接
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>
🔗 相关文档参考
核心标准文档
-
前端实现标准:
docs/guidelines/implementation/frontend.md- Atomic Design目录结构定义
- API调用和状态管理规范
-
组件设计指南:
docs/guidelines/design/11_frontend-component-design-guidelines.md- 组件层次职责划分
- 3次规则详细说明
-
命名规范指南:
docs/guidelines/design/10_naming-conventions-guidelines.md- 文件、组件、变量命名规则
AI配置文档
-
Copilot基础指令:
.github/copilot-instructions.md- AI行为准则和安全原则
-
组件生成提示词:
.github/prompts/atomic-component.prompt.md- 标准化组件生成指令
实现教程文档
-
表单验证教程:
frontend/docs/guides/validation.md- 基于Zod的验证实现
-
国际化教程:
frontend/docs/guides/i18n.md- Vue I18n配置和使用
设计系统资源
-
Storybook组件库:
npm run storybook(本地访问)- 所有可用组件的交互式文档
-
设计令牌定义:
frontend/src/assets/styles/tokens.css- CSS自定义属性定义
📞 支持与升级
文档更新机制
- 版本控制:本指南随项目架构演进定期更新
- 变更记录:重大架构变更需同步更新本指南
- 团队同步:更新后需通过团队评审并通知所有成员
问题反馈流程
- 发现不一致:记录具体场景和期望行为
- 检查文档:确认是否文档缺失或错误
- 提交修正:通过PR更新相关文档
- 团队通知:变更后同步所有相关方
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包装规范、设计令牌系统