# 基础组件 **本文引用的文件** - [Button.vue](file://fms-vue/src/components/ui/button/Button.vue) - [button-group.vue](file://fms-vue/src/components/ui/button-group/button-group.vue) - [Input.vue](file://fms-vue/src/components/ui/input/Input.vue) - [Tag.vue](file://fms-vue/src/components/ui/tag/Tag.vue) - [Spin.vue](file://fms-vue/src/components/ui/spin/Spin.vue) - [Form.vue](file://fms-vue/src/components/ui/form/Form.vue) - [index.js](file://fms-vue/src/theme/index.js) - [presets.js](file://fms-vue/src/theme/presets.js) - [tokens.css](file://fms-vue/src/theme/tokens.css) ## 目录 1. [简介](#简介) 2. [项目结构](#项目结构) 3. [核心组件](#核心组件) 4. [架构总览](#架构总览) 5. [详细组件分析](#详细组件分析) 6. [依赖关系分析](#依赖关系分析) 7. [性能考量](#性能考量) 8. [故障排查指南](#故障排查指南) 9. [结论](#结论) 10. [附录](#附录) ## 简介 本章节面向 FMS 前端工程中的基础 UI 组件,聚焦按钮、输入框、标签、加载指示器与表单容器等高频交互元素。文档从设计理念、API 接口、属性配置、事件处理、样式定制、可访问性(a11y)与响应式特性等方面进行全面说明,并提供组合使用示例与性能优化建议,帮助开发者快速、正确地集成与扩展这些基础组件。 ## 项目结构 FMS 的 UI 组件位于 fms-vue 工程的 src/components/ui 目录下,采用“按功能分目录”的组织方式:每个组件一个独立目录,包含 Vue 组件与对应样式;主题与令牌定义集中在 theme 目录,便于统一风格与深浅色适配。 ```mermaid graph TB subgraph "UI 组件" B["Button"] BG["ButtonGroup"] I["Input"] T["Tag"] S["Spin"] F["Form"] end subgraph "主题系统" TI["theme/index.js"] TP["theme/presets.js"] TK["theme/tokens.css"] end B --> TI BG --> TI I --> TI T --> TI S --> TI F --> TI TI --> TP TI --> TK ``` 图表来源 - [Button.vue:1-69](file://fms-vue/src/components/ui/button/Button.vue#L1-L69) - [button-group.vue:1-83](file://fms-vue/src/components/ui/button-group/button-group.vue#L1-L83) - [Input.vue:1-370](file://fms-vue/src/components/ui/input/Input.vue#L1-L370) - [Tag.vue:1-86](file://fms-vue/src/components/ui/tag/Tag.vue#L1-L86) - [Spin.vue:1-93](file://fms-vue/src/components/ui/spin/Spin.vue#L1-L93) - [Form.vue:1-128](file://fms-vue/src/components/ui/form/Form.vue#L1-L128) - [index.js](file://fms-vue/src/theme/index.js) - [presets.js](file://fms-vue/src/theme/presets.js) - [tokens.css](file://fms-vue/src/theme/tokens.css) 章节来源 - [Button.vue:1-69](file://fms-vue/src/components/ui/button/Button.vue#L1-L69) - [button-group.vue:1-83](file://fms-vue/src/components/ui/button-group/button-group.vue#L1-L83) - [Input.vue:1-370](file://fms-vue/src/components/ui/input/Input.vue#L1-L370) - [Tag.vue:1-86](file://fms-vue/src/components/ui/tag/Tag.vue#L1-L86) - [Spin.vue:1-93](file://fms-vue/src/components/ui/spin/Spin.vue#L1-L93) - [Form.vue:1-128](file://fms-vue/src/components/ui/form/Form.vue#L1-L128) - [index.js](file://fms-vue/src/theme/index.js) - [presets.js](file://fms-vue/src/theme/presets.js) - [tokens.css](file://fms-vue/src/theme/tokens.css) ## 核心组件 本节概述各基础组件的职责与能力边界: - Button:提供多种视觉变体、禁用态、加载态、块级模式与原生表单类型支持,内置无障碍提示。 - ButtonGroup:将多个按钮组合为连续控件组,支持水平/垂直排列,自动处理圆角与焦点层级。 - Input:支持文本、密码、数字、多行文本四种模式;具备清除、字数统计、前缀/后缀插槽、拖拽调整高度、键盘操作与校验状态。 - Tag:展示轻量标签,支持关闭、禁用、链接跳转与图标插槽。 - Spin:提供延迟显示的加载指示器,支持包裹内容遮罩或独立指示器两种形态。 - Form:表单容器,提供布局、网格列数、对齐、必填标记、校验时机与全量校验能力,并通过 provide/inject 向子项下发上下文。 章节来源 - [Button.vue:1-69](file://fms-vue/src/components/ui/button/Button.vue#L1-L69) - [button-group.vue:1-83](file://fms-vue/src/components/ui/button-group/button-group.vue#L1-L83) - [Input.vue:1-370](file://fms-vue/src/components/ui/input/Input.vue#L1-L370) - [Tag.vue:1-86](file://fms-vue/src/components/ui/tag/Tag.vue#L1-L86) - [Spin.vue:1-93](file://fms-vue/src/components/ui/spin/Spin.vue#L1-L93) - [Form.vue:1-128](file://fms-vue/src/components/ui/form/Form.vue#L1-L128) ## 架构总览 基础组件围绕“主题令牌 + 语义化 DOM + 无障碍属性”构建: - 主题层:通过 tokens.css 暴露 CSS 变量(如控制半径、尺寸、颜色),由 presets.js 预设默认值,index.js 负责导出与注入。 - 组件层:各组件以语义化标签渲染(button/input/span/div),结合 aria-* 属性提升可访问性。 - 交互层:通过 Vue 的 props/emits/slots 暴露 API,事件冒泡到父组件进行业务处理。 ```mermaid graph LR TK["tokens.css
CSS 变量"] --> P["presets.js
主题预设"] P --> I["index.js
主题入口"] I --> C1["Button"] I --> C2["ButtonGroup"] I --> C3["Input"] I --> C4["Tag"] I --> C5["Spin"] I --> C6["Form"] ``` 图表来源 - [tokens.css](file://fms-vue/src/theme/tokens.css) - [presets.js](file://fms-vue/src/theme/presets.js) - [index.js](file://fms-vue/src/theme/index.js) - [Button.vue:1-69](file://fms-vue/src/components/ui/button/Button.vue#L1-L69) - [button-group.vue:1-83](file://fms-vue/src/components/ui/button-group/button-group.vue#L1-L83) - [Input.vue:1-370](file://fms-vue/src/components/ui/input/Input.vue#L1-L370) - [Tag.vue:1-86](file://fms-vue/src/components/ui/tag/Tag.vue#L1-L86) - [Spin.vue:1-93](file://fms-vue/src/components/ui/spin/Spin.vue#L1-L93) - [Form.vue:1-128](file://fms-vue/src/components/ui/form/Form.vue#L1-L128) ## 详细组件分析 ### 按钮 Button - 设计理念:统一的视觉语言与行为语义,兼顾表单场景与通用操作。 - 关键属性 - type:视觉变体(主按钮、次要、描边、幽灵、危险、链接)。 - disabled:禁用态。 - loading:加载态,内部显示旋转图标并禁用交互。 - block:块级模式,占满整行宽度。 - htmlType:原生 button/submit/reset,用于表单提交/重置。 - 事件 - 透传原生点击事件至父组件。 - 可访问性 - 在加载时设置 aria-busy,辅助技术可感知忙碌状态。 - 样式定制 - 通过 CSS 类名 button/button-{type}/button-block/button-loading 覆盖样式。 - 与主题变量联动(如圆角、间距、颜色)。 - 组合使用 - 与 ButtonGroup 组合实现工具栏、分页、分段控制器等。 - 性能 - 仅计算必要 class,避免多余重排。 ```mermaid classDiagram class Button { +type +disabled +loading +block +htmlType +click() } ``` 图表来源 - [Button.vue:1-69](file://fms-vue/src/components/ui/button/Button.vue#L1-L69) 章节来源 - [Button.vue:1-69](file://fms-vue/src/components/ui/button/Button.vue#L1-L69) ### 按钮组 ButtonGroup - 设计理念:将一组按钮视为单一控件组,保证视觉连贯性与键盘可达性。 - 关键属性 - orientation:horizontal | vertical,控制排列方向。 - 行为 - 自动去除相邻按钮重叠边框,首尾按钮保留圆角。 - 聚焦时提升 z-index,确保焦点可见。 - 可访问性 - role="group",data-orientation 标识方向,便于测试与样式定位。 - 样式定制 - 通过 .button-group / .button-group-vertical 及 :deep(.button) 选择器覆盖。 ```mermaid flowchart TD Start(["渲染"]) --> CheckOri{"方向?"} CheckOri --> |水平| H["横向排列
去圆角+贴合"] CheckOri --> |垂直| V["纵向排列
去圆角+贴合"] H --> Focus["聚焦时提升层级"] V --> Focus Focus --> End(["完成"]) ``` 图表来源 - [button-group.vue:1-83](file://fms-vue/src/components/ui/button-group/button-group.vue#L1-L83) 章节来源 - [button-group.vue:1-83](file://fms-vue/src/components/ui/button-group/button-group.vue#L1-L83) ### 输入框 Input - 设计理念:高内聚的输入体验,覆盖常见输入场景与交互细节。 - 关键属性 - modelValue:双向绑定值。 - type:default | password | number | textarea。 - disabled / readonly:禁用/只读。 - status:校验状态 '' | error | warning。 - allowClear:有值时显示清除按钮(hover/focus 时出现)。 - showCount / maxlength:字数统计。 - rows:textarea 初始行数。 - autocomplete:浏览器自动填充语义。 - 事件 - update:modelValue、change、blur、focus、clear。 - 特殊能力 - 密码模式:显示/隐藏切换,带无障碍标签。 - 数字模式:中间态容错(允许小数点过渡),失焦时提交数值。 - 多行文本:拖拽调整高度,键盘上下/Home 微调,requestAnimationFrame 节流更新。 - 前缀/后缀插槽:增强输入语义与操作。 - 可访问性 - 错误状态设置 aria-invalid。 - 密码切换按钮提供 aria-label 与 aria-pressed。 - 拖拽手柄提供 role="slider" 与相关 aria 属性。 - 样式定制 - 通过 input-wrapper/input-focused/input-disabled/input-textarea 等类名覆盖。 - 与主题变量联动(尺寸、圆角、颜色)。 ```mermaid sequenceDiagram participant U as "用户" participant I as "Input" U->>I : 输入/聚焦/失焦/清除 I->>I : 校验状态/计数/数字归一化 I-->>U : 触发 change/update : modelValue/clear Note over I,U : 密码模式切换/拖拽高度/键盘微调 ``` 图表来源 - [Input.vue:1-370](file://fms-vue/src/components/ui/input/Input.vue#L1-L370) 章节来源 - [Input.vue:1-370](file://fms-vue/src/components/ui/input/Input.vue#L1-L370) ### 标签 Tag - 设计理念:轻量信息标注,支持关闭与链接跳转。 - 关键属性 - variant:视觉变体(default/secondary/outline/danger/ghost)。 - closable:是否显示关闭按钮。 - disabled:禁用态。 - href:传入后渲染为 ,支持跳转。 - 事件 - close:点击关闭时触发,可通过 preventDefault 阻止隐藏。 - 可访问性 - 关闭按钮 role="button",支持 Enter/Space 触发。 - 禁用态设置 aria-disabled。 - 样式定制 - 通过 tag/tag-{variant}/tag-disabled/tag-hidden 类名覆盖。 ```mermaid flowchart TD Click["点击关闭"] --> Disabled{"禁用?"} Disabled --> |是| Stop["忽略"] Disabled --> |否| Emit["触发 close"] Emit --> Prevent{"是否阻止默认?"} Prevent --> |是| Keep["保持可见"] Prevent --> |否| Hide["隐藏自身"] ``` 图表来源 - [Tag.vue:1-86](file://fms-vue/src/components/ui/tag/Tag.vue#L1-L86) 章节来源 - [Tag.vue:1-86](file://fms-vue/src/components/ui/tag/Tag.vue#L1-L86) ### 加载指示器 Spin - 设计理念:防抖短请求闪烁,提供两种形态(独立指示器/包裹内容遮罩)。 - 关键属性 - spinning:是否加载中。 - delay:延迟显示毫秒数,避免短暂请求导致闪烁。 - description:加载文案。 - 行为 - 有默认插槽时,作为容器包裹内容并居中显示遮罩;否则直接渲染指示器。 - 卸载时清理定时器。 - 可访问性 - 根节点 aria-busy 与 aria-live="polite",描述区域 role="status"。 - 样式定制 - 通过 spin/spin-nested/spin-spinning 类名覆盖。 ```mermaid flowchart TD Start(["spinning/delay 变化"]) --> ClearTimer["清理旧定时器"] ClearTimer --> CheckSpinning{"spinning?"} CheckSpinning --> |否| SetInactive["active=false"] CheckSpinning --> |是| HasDelay{"delay>0?"} HasDelay --> |是| Wait["setTimeout(delay)"] HasDelay --> |否| SetActive["active=true"] Wait --> SetActive SetInactive --> End(["结束"]) SetActive --> End ``` 图表来源 - [Spin.vue:1-93](file://fms-vue/src/components/ui/spin/Spin.vue#L1-L93) 章节来源 - [Spin.vue:1-93](file://fms-vue/src/components/ui/spin/Spin.vue#L1-L93) ### 表单容器 Form - 设计理念:集中管理表单数据、规则与校验流程,提供灵活布局与网格能力。 - 关键属性 - model:表单数据对象。 - rules:表单级校验规则(字段级优先级更高)。 - layout:horizontal | vertical。 - labelAlign:label 对齐 left | right。 - labelWidth:label 宽度(横向布局生效)。 - columns:网格列数(>1 启用栅格布局)。 - maxWidth:最大宽度限制。 - requiredMark:必填红星标记。 - validateTrigger:change | blur。 - 事件 - submit:校验通过后触发,携带模型副本。 - submitFailed:校验失败,携带 values 与 errorFields。 - reset:重置后触发。 - 能力 - 提供 validateAll 方法,返回带错误的字段列表。 - 通过 provide('fms-form') 向子项下发上下文(model/rules/layout/对齐/列数/必填标记/校验时机/注册注销字段)。 - 可访问性 - 原生 form 语义,配合子项的 a11y 属性形成完整无障碍链路。 - 样式定制 - 通过 fms-form/fms-form-{layout}/fms-form-grid 类名覆盖。 ```mermaid sequenceDiagram participant Parent as "父组件" participant Form as "Form" participant Item as "FormItem(子项)" Parent->>Form : 提交/重置 Form->>Form : validateAll() loop 遍历已注册字段 Form->>Item : validate() Item-->>Form : errors[] end alt 无错误 Form-->>Parent : emit("submit", model) else 有错误 Form-->>Parent : emit("submitFailed", {values, errorFields}) end ``` 图表来源 - [Form.vue:1-128](file://fms-vue/src/components/ui/form/Form.vue#L1-L128) 章节来源 - [Form.vue:1-128](file://fms-vue/src/components/ui/form/Form.vue#L1-L128) ## 依赖关系分析 - 组件间耦合 - ButtonGroup 依赖 Button 的类名约定(.button)以实现无缝拼接。 - Form 通过 provide/inject 与子项协作,但当前仓库未包含 Form.Item 的具体实现,因此此处仅描述容器职责。 - 外部依赖 - 图标来自 @lucide/vue(Loader/X/Eye/EyeOff/MoveDiagonal2)。 - 样式基于 SCSS 模块化导入,配合主题变量。 - 主题依赖 - 所有组件通过主题层提供的 CSS 变量保持一致的视觉风格与深浅色适配。 ```mermaid graph LR L["@lucide/vue"] --> B["Button"] L --> I["Input"] L --> T["Tag"] L --> S["Spin"] TK["tokens.css"] --> Theme["主题层"] Theme --> B Theme --> I Theme --> T Theme --> S Theme --> F["Form"] ``` 图表来源 - [Button.vue:1-69](file://fms-vue/src/components/ui/button/Button.vue#L1-L69) - [Input.vue:1-370](file://fms-vue/src/components/ui/input/Input.vue#L1-L370) - [Tag.vue:1-86](file://fms-vue/src/components/ui/tag/Tag.vue#L1-L86) - [Spin.vue:1-93](file://fms-vue/src/components/ui/spin/Spin.vue#L1-L93) - [Form.vue:1-128](file://fms-vue/src/components/ui/form/Form.vue#L1-L128) - [tokens.css](file://fms-vue/src/theme/tokens.css) 章节来源 - [Button.vue:1-69](file://fms-vue/src/components/ui/button/Button.vue#L1-L69) - [Input.vue:1-370](file://fms-vue/src/components/ui/input/Input.vue#L1-L370) - [Tag.vue:1-86](file://fms-vue/src/components/ui/tag/Tag.vue#L1-L86) - [Spin.vue:1-93](file://fms-vue/src/components/ui/spin/Spin.vue#L1-L93) - [Form.vue:1-128](file://fms-vue/src/components/ui/form/Form.vue#L1-L128) - [tokens.css](file://fms-vue/src/theme/tokens.css) ## 性能考量 - 输入框 Input - 数字模式在输入过程中保留中间态,减少不必要的 Number 转换与回退。 - 拖拽调整高度使用 requestAnimationFrame 节流,避免频繁重绘。 - 仅在必要时计算 hasValue/showClear/countText 等派生状态。 - 加载指示器 Spin - 通过 delay 防止短请求导致的闪烁;卸载时清理定时器,避免内存泄漏。 - 按钮 Button - 使用 computed 合并 class,减少模板中条件判断开销。 - 表单 Form - validateAll 并行校验所有字段,缩短整体校验耗时。 - 主题与样式 - 通过 CSS 变量与模块化 SCSS 减少重复样式,利于缓存与复用。 [本节为通用性能指导,不直接分析具体代码片段] ## 故障排查指南 - 按钮不可点击 - 检查 disabled/loading 状态;确认 htmlType 是否符合预期。 - 参考:[Button.vue:1-69](file://fms-vue/src/components/ui/button/Button.vue#L1-L69) - 输入框数值异常 - 数字模式下中间态允许小数点,失焦才会提交数值;如需严格格式,可在父组件监听 change 做二次校验。 - 参考:[Input.vue:107-150](file://fms-vue/src/components/ui/input/Input.vue#L107-L150) - 多行文本拖拽卡顿 - 确认未同时大量更新其他视图;组件已使用 requestAnimationFrame 节流。 - 参考:[Input.vue:166-238](file://fms-vue/src/components/ui/input/Input.vue#L166-L238) - 标签关闭无效 - 若父组件在 close 事件中调用 preventDefault,则不会隐藏;请检查事件处理逻辑。 - 参考:[Tag.vue:40-56](file://fms-vue/src/components/ui/tag/Tag.vue#L40-L56) - 加载指示器闪烁 - 适当增大 delay 以避免短请求闪烁;或在父层统一控制 spinning。 - 参考:[Spin.vue:18-44](file://fms-vue/src/components/ui/spin/Spin.vue#L18-L44) - 表单校验结果不符合预期 - 确认 validateTrigger 与子项触发时机一致;提交前可调用 validateAll 强制校验。 - 参考:[Form.vue:64-92](file://fms-vue/src/components/ui/form/Form.vue#L64-L92) 章节来源 - [Button.vue:1-69](file://fms-vue/src/components/ui/button/Button.vue#L1-L69) - [Input.vue:107-150](file://fms-vue/src/components/ui/input/Input.vue#L107-L150) - [Input.vue:166-238](file://fms-vue/src/components/ui/input/Input.vue#L166-L238) - [Tag.vue:40-56](file://fms-vue/src/components/ui/tag/Tag.vue#L40-L56) - [Spin.vue:18-44](file://fms-vue/src/components/ui/spin/Spin.vue#L18-L44) - [Form.vue:64-92](file://fms-vue/src/components/ui/form/Form.vue#L64-L92) ## 结论 FMS 基础组件以“语义化 + 可访问性 + 主题化”为核心设计原则,提供了稳定、易用且可扩展的交互基元。通过统一的 API 与样式体系,开发者可以快速搭建一致的界面,并在复杂场景中保持良好的性能与可维护性。建议在项目中优先使用这些基础组件,并结合主题系统进行品牌化定制。 [本节为总结性内容,不直接分析具体代码片段] ## 附录 - 主题适配与深浅色 - 通过 tokens.css 暴露 CSS 变量,presets.js 提供默认值,index.js 负责导出与注入。 - 建议在应用启动时按需切换主题预设,即可全局生效。 - 参考:[tokens.css](file://fms-vue/src/theme/tokens.css)、[presets.js](file://fms-vue/src/theme/presets.js)、[index.js](file://fms-vue/src/theme/index.js) - 最佳实践 - 表单:使用 Form 统一管理 model/rules/校验时机;提交前调用 validateAll。 - 输入:合理使用 type/status/allowClear/showCount,提升用户体验。 - 按钮:在异步操作中开启 loading,完成后关闭,避免重复提交。 - 标签:在需要可关闭的场景使用 closable,并通过 close 事件控制显隐。 - 加载:对短请求使用 delay 避免闪烁;长任务使用 Spin 包裹内容。 章节来源 - [tokens.css](file://fms-vue/src/theme/tokens.css) - [presets.js](file://fms-vue/src/theme/presets.js) - [index.js](file://fms-vue/src/theme/index.js) - [Form.vue:1-128](file://fms-vue/src/components/ui/form/Form.vue#L1-L128) - [Input.vue:1-370](file://fms-vue/src/components/ui/input/Input.vue#L1-L370) - [Button.vue:1-69](file://fms-vue/src/components/ui/button/Button.vue#L1-L69) - [Tag.vue:1-86](file://fms-vue/src/components/ui/tag/Tag.vue#L1-L86) - [Spin.vue:1-93](file://fms-vue/src/components/ui/spin/Spin.vue#L1-L93)