前言
做前端架构的人要不要懂组件库设计?我的回答是 要——不是去抄 Element Plus / Ant Design,而是建立”50 个组件怎么保持 API 一致性、视觉统一性、可维护性”的工程哲学。原因有三:
- 简历里 iView / FinUI 是真实项目。设计 Token 体系 / 主题定制 / 文档化 决定组件库能用多久。
- 组件库是团队的”基础设施”。50 个业务方依赖你的组件库,改一个 API = 改 50 个项目的代码。架构师必须有”破坏性变更控制”思维。
- 可访问性 / 国际化 / 暗色模式 是组件库的必答题,不是选答题。Element Plus v3 / Ant Design v5 都在强调这几点。
这一篇是『前端架构修仙路』的第 23 篇。我跳过具体组件 API(不讲 Button 怎么写),用设计哲学 + 真实经验 + 决策表,把 Token 体系 / 主题 / 文档 / API 一致性 / 版本管理讲透。下一篇深度聊中后台开发模式。
一、组件库三大核心目标
二、Design Token:组件库的灵魂
2.1 Token 三大层级
// 1. 基础 Token(原子层,不变)
const baseTokens = {
'color-blue-500': '#1a73e8',
'color-blue-600': '#1557b0',
'space-1': '4px',
'space-2': '8px',
'radius-sm': '4px',
'radius-md': '8px',
'font-size-sm': '12px',
};
// 2. 语义 Token(基于基础 Token,可换主题)
const semanticTokens = {
'color-primary': 'var(--color-blue-500)',
'color-primary-hover': 'var(--color-blue-600)',
'spacing-small': 'var(--space-2)',
'radius-default': 'var(--radius-md)',
'text-sm': 'var(--font-size-sm)',
};
// 3. 组件 Token(具体组件,默认用语义 Token)
const buttonTokens = {
'button-primary-bg': 'var(--color-primary)',
'button-primary-bg-hover': 'var(--color-primary-hover)',
'button-padding': 'var(--spacing-small)',
};
架构师心法:业务方只引语义 Token——color: var(--color-primary) 而不是 var(--color-blue-500)。主题切换时只改 baseToken——蓝变绿一键搞定。
2.2 主题切换实战
// 暗色模式:换 baseToken
:root[data-theme="dark"] {
--color-blue-500: #4a9eff; /* 暗色蓝要更亮 */
--color-blue-600: #6bb0ff;
}
// 客户主题定制:比如医院绿色主题
:root[data-theme="hospital"] {
--color-blue-500: #00a878; /* 医院绿 */
--color-blue-600: #008866;
}
生产案例:iView 改 Ant Design 风格时,只换了 baseToken——3 天迁移完成。没 Token 体系的组件库 = 改一个颜色改 200 个文件。
三、API 一致性:组件库的灵魂
3.1 五大一致性原则
所有组件遵循:
1. props 命名:size / type / variant / disabled
2. 事件命名:onClick / onChange / onSubmit
3. 状态:loading / disabled / readonly / error
4. 受控/非受控:value / defaultValue 都支持
5. 回调参数:(value, event) 顺序统一
// ✅ 一致性
<Input value={val} onChange={setVal} size="small" disabled />
<Select value={val} onChange={setVal} size="small" disabled />
<DatePicker value={val} onChange={setVal} size="small" disabled />
// ❌ 不一致(灾难)
<Input val={val} onChangeVal={setVal} small />
<Select v={val} onSel={setSel} size="small" />
<DatePicker val={val} onDateChange={setVal} />
架构师规则:API 一致性 > 单一组件的完美性。一个组件做得很完美但 API 与其他组件不一致 = 团队学习成本 × 50。
四、文档与示例:Storybook
// Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
const meta: Meta<typeof Button> = {
title: 'Components/Button',
component: Button,
argTypes: {
size: { control: 'select', options: ['small', 'medium', 'large'] },
variant: { control: 'select', options: ['primary', 'secondary', 'danger'] },
disabled: { control: 'boolean' },
},
};
export default meta;
type Story = StoryObj<typeof Button>;
export const Primary: Story = {
args: { variant: 'primary', children: 'Primary Button' },
};
export const Secondary: Story = {
args: { variant: 'secondary', children: 'Secondary Button' },
};
Storybook 三件套:
- 每个组件有 stories 文件
- Controls 面板可以交互调试 props
- Docs 页面自动生成 props 表格
五、版本管理与 Breaking Change
5.1 SemVer 规则
major: 破坏性变更(API 不兼容)
minor: 新功能(向后兼容)
patch: Bug 修复
5.2 Breaking Change 控制
// v1.x Button
<Button onClick={handleClick}>Click</Button>
// v2.0 加 size prop(非破坏性,minor)
// v3.0 onClick 改名为 onPress(破坏性,major)
/* ⚠️ 必须在 v2.x 文档中预告 + 提供 codemod */
<Button onPress={handlePress}>Click</Button>
// codemod.ts: 自动迁移
transform: (file, api) => {
const j = api.jscodeshift;
return j(file.source)
.find(j.JSXElement, { openingElement: { name: { name: 'Button' } } })
.forEach(path => {
// onClick → onPress
})
.toSource();
};
架构师心法:破坏性变更 = 用户升级 = 团队信任。Codemod 自动化迁移让用户升级 = 跑一行命令。
六、可访问性(A11y)
// ✅ 关键组件都加 a11y 属性
<button aria-label="关闭弹窗" aria-expanded={isOpen} aria-controls="modal-content">
<X />
</button>
<select aria-required={required} aria-invalid={!!error}>
<option>...</option>
</select>
WCAG 2.1 AA 必填项:
- 颜色对比度 ≥ 4.5:1(普通文字)/ 3:1(大文字)
- 键盘可访问:Tab 顺序合理 / Enter / Space / Esc / 方向键
- aria-label / aria-describedby:屏幕阅读器可读
- focus ring 可见:键盘焦点不能消失
七、生产实战:iView / FinUI 设计经验
iView(柔宇时期):
- 2016 年开始维护,30+ 组件
- 2018 年 v3.0 重构为 Vue 单文件组件
- 2024 年迁移到 Vue 3 + Composition API
- 核心经验:Design Token 一定要从 day 1 设计——后期加 Token 体系 = 重写 50 个组件
FinUI(顺丰时期):
- 50+ 组件 + 业务组件库
- 大表格 FinSpread(已并入 FinUI)
- 主题定制支持多家客户品牌色
- 核心经验:API 一致性 PR review 必查——v2 改 size prop 后被投诉”为什么 table 不支持”,团队重写 30 个组件对齐 API
八、踩坑提醒(资深架构师请重点看)
- 不要从 day 1 就建 100 个组件。先做 5-10 个核心组件(Button / Input / Select / Table / Form),业务用起来后再加。
- 不要用同一个 prop 名表达不同含义。
size="small"在 Button 是 padding,在 Table 是字体大小——应该分开命名(Button 用size,Table 用density)。 - 不要忽略 A11y。WCAG 2.1 AA 是企业级组件库的入场券——政府 / 医疗 / 银行客户必查。
- 不要让 breaking change 太突然。提前 1 个 minor 版本预告 + 提供 codemod + 文档示例,让用户有时间迁移。
- 不要忘记 bundle size。每个组件都要 tree-shakable——按需引入
import { Button } from 'finui'而不是import * from 'finui'。
总结
这一篇用 6 个关键事实把组件库设计串起来:
- Design Token 三层架构:基础 / 语义 / 组件 Token,主题切换只改基础。
- API 一致性 > 单组件完美:所有组件同款 props / 事件 / 状态命名。
- Storybook 文档:每个组件 stories + Controls 调试 + Docs 自动生成。
- SemVer + Codemod:Breaking change 必预告 + 自动迁移。
- WCAG 2.1 AA 是入场券:键盘 / aria / 颜色对比度全要。
- 生产经验:iView 30+ 组件、FinUI 50+ 组件,核心都是Token 体系 + API 一致性。
下一篇:中后台开发模式——表单 / 表格 / ECharts,800+ 页面 ERP 沉淀。
5 道重点面试问题方向
Q1(答案):Design Token 三层架构是什么?为什么基础 / 语义 / 组件要分开?
A:三层架构:① 基础 Token(原子层) — 颜色 / 间距 / 字号 / 圆角的具体值,如
color-blue-500: #1a73e8;② 语义 Token(基于基础) — 业务场景的别名,如color-primary: var(--color-blue-500);③ 组件 Token(具体组件) — 组件内部用,如button-primary-bg: var(--color-primary)。为什么分开:业务方只引语义 Token,主题切换时只改基础 Token。案例:某组件库没 Token 体系,改暗色模式要改 200 个文件;有 Token 体系后改 1 个 baseToken 切换全主题,3 天迁移完成。Q2(思考):API 一致性 vs 单组件完美,哪个更重要?怎么保证 50 个组件 API 一致?
A:API 一致性 > 单组件完美。反例:某组件库 v2 各组件 props 命名混乱(Input 用
val/ Select 用v/ DatePicker 用value),团队学习成本 × 50。保证一致性的方法:① PR review 必查 — 新组件必须和已有组件 props 命名一致;② codemod 工具自动对齐 — 旧组件被新组件风格统一;③ API 文档化 — 内部 wiki 列出所有组件的 props / 事件命名;④ 设计 Token 体系约束 — 让”颜色 / 间距”无法自定义,强制走 Token。Q3(思考):Breaking Change 怎么处理?Codemod 的作用是什么?
A:Breaking change = 用户升级成本。正确处理:① 提前预告 — 在下个 minor 版本文档标注”v3.0 will change X”;② 提供 codemod 工具 — 用户跑
npx @finui/codemod v2-to-v3自动迁移;③ 保留兼容期 — 旧 API 在 major 版本前继续工作,只 deprecate 警告;④ 文档示例 — 给升级前后的代码 diff。Codemod 的作用:自动重写代码。某组件库 v2 改 size 命名,5 个项目 30 万行业务代码,1 个 codemod 跑 1h 完成升级——没有 codemod 要手动改 3 周。Q4(思考):WCAG 2.1 AA 对企业级组件库意味着什么?哪些是必做项?
A:WCAG 2.1 AA 是企业级组件库的入场券——政府 / 医疗 / 银行客户必查,不合规不能上他们的项目。必做项:① 颜色对比度 ≥ 4.5:1(普通文字) / ≥ 3:1(大文字);② 键盘可访问 — Tab / Shift+Tab / Enter / Space / Esc / 方向键都要支持;③ aria 属性 — aria-label / aria-describedby / aria-expanded / aria-controls / aria-required / aria-invalid;④ focus ring 可见 — 键盘焦点不能消失(不要
outline: none);⑤ 屏幕阅读器测试 — 用 VoiceOver / NVDA 实际测试。Q5(思考):你在 iView / FinUI 的组件库设计里,有什么具体的经验教训?踩过哪些坑?
A:iView(柔宇,30+ 组件):① Design Token 一定要 day 1 设计 — 后期加 Token = 重写 50 个组件;② Vue 2 → Vue 3 迁移 踩坑多,Composition API +
<script setup>让 30 个组件代码减半。FinUI(顺丰,50+ 组件):① API 一致性 PR review 必查 — v2 改 size prop 后被投诉”为什么 table 不支持”,重写 30 个组件对齐;② 大表格 FinSpread(300 列 × 500 行)用虚拟滚动 + 列虚拟化,从 800ms 优化到 50ms;③ 跨客户主题定制 用 Design Token 体系,3 天切换品牌色。共同教训:Breaking change 必预告 + codemod 自动化——信任建立一次需要 3 年,毁掉一次只要 1 个 release。
💡 每道题后面都有 AI 助手按钮,一键拿到详细答案。
参考资料
- Design Tokens (Design Tokens Community Group) — Design Token 社区标准
- Storybook Documentation — Storybook 官方文档
- WCAG 2.1 (W3C) — W3C 可访问性标准
- Element Plus Documentation — Element Plus 组件库参考
- Ant Design Design Tokens — Ant Design 主题系统
- Material Design Tokens (Material 3) — Material Design 3 token 系统