Files
workspace/code/fms/.codebuddy/plans/button-enhance_280ee511.md
T
2026-08-16 22:01:32 +08:00

100 lines
6.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: button-enhance
overview: 为 Button 组件补齐行为层能力:nativeType、disabled、loading、size、block 五个 prop,配套样式与 token,并更新 App.vue 展示页示例。
todos:
- id: add-size-tokens
content: 在 tokens.css 新增 sm/lg 尺寸、内边距与字号 token
status: completed
- id: button-props
content: 改造 button.vue:新增 nativeType、disabled、loading、size、block 五个 prop 与 spinner 模板
status: completed
dependencies:
- add-size-tokens
- id: button-styles
content: 扩展 index.scss:实现 size、block、disabled、loading 与 spinner 动画样式
status: completed
dependencies:
- add-size-tokens
- id: app-demo
content: 更新 App.vue 展示页补充禁用、加载、尺寸、通栏示例
status: completed
dependencies:
- button-props
- button-styles
---
## 产品概述
为现有 Button 组件补齐行为层能力,使其从"纯视觉变体"升级为可直接用于表单和异步场景的交互组件,同时保持当前克制、token 驱动的设计语言。
## 核心功能
- **原生 type 控制**:新增 `nativeType` prop,默认 `button`,避免放入表单时误触发表单提交
- **禁用态**:新增 `disabled` prop,禁用点击、hover/active 效果,光标提示 `not-allowed`
- **加载态**:新增 `loading` prop,显示内联 SVG spinner,标记 `aria-busy`,加载期间禁止交互且布局宽度不跳动
- **尺寸三档**:新增 `size` prop(small / default / large),通过 token 驱动高度、内边距与字号
- **通栏模式**:新增 `block` prop,按钮占满整行宽度,适配表单底部操作区
## 技术栈
- Vue 3 `<script setup>` 组合式 API
- Sass/SCSS(项目已装 `sass ^1.102.0`,沿用 `<style scoped lang="scss">` + `@use './index.scss'` 模式)
- 设计 token 驱动(CSS 变量,命名沿用 `--fms-` 前缀)
## 实现方案
### 总体策略
不改动现有 6 种视觉变体(default/secondary/outline/ghost/danger/link)和基础交互,只在组件上**追加**行为层 prop 与对应 class,向后完全兼容。尺寸三档、禁用态、加载态全部通过 token 与 scoped 样式实现,单一来源,符合项目既有模式。
### 关键决策
- **`nativeType` 默认 `button`**:HTML 原生 `<button>` 默认 `type="submit"`,显式设默认值消除表单误提交隐患,同时保留透传覆盖能力。
- **loading 复用 disabled 语义**:`loading` 时计算属性 `isDisabled = disabled || loading`,统一走原生 `:disabled` 路径,避免重复点击;同时挂 `aria-busy` 供屏幕阅读器识别。
- **spinner 用内联 SVG**:项目无图标库,参考 `ThemeToggle.vue`/`ColorThemePicker.vue` 的内联 `<svg>` 写法,不引入新依赖;spinner 前置、文字保留占位,避免加载时按钮宽度跳变。
- **尺寸走 token 而非写死数值**:新增 `--fms-control-height-sm/lg`、`--fms-control-padding-x-sm/lg`、`--fms-font-size-sm/lg` 三组 token,与现有 `--fms-control-height`(default)形成三档体系,延续「font-size 已 token 化」的既有约定。
- **disabled 态覆盖 hover/active**:`:disabled` 下取消 `transform: scale(0.97)` 与背景/文字颜色变化,保证「看起来不能点」;spinner 旋转动画纳入 `prefers-reduced-motion: reduce` 降级,与现有动效处理一致。
## 实现要点
### button.vue 改造
- 新增 props:`nativeType`(String,默认 `'button'`)、`disabled`(Boolean,默认 `false`)、`loading`(Boolean,默认 `false`)、`size`(String,默认 `'default'`,可选 `'small' | 'large'`)、`block`(Boolean,默认 `false`)。
- `classes` 计算属性在原有 `button`、`button-${type}` 基础上追加:`size !== 'default'` 时加 `button-${size}`,`block` 加 `button-block`,`loading` 加 `button-loading`。
- 模板绑定 `:type="nativeType"`、`:disabled="isDisabled"`、`:aria-busy="loading || undefined"`,`loading` 时在 `<slot>` 前渲染 spinner SVG。
- 沿用 `<style scoped lang="scss">@use './index.scss';</style>` 不改变隔离方式。
### index.scss 扩展
- 新增 `.button-small` / `.button-large`:分别引用 sm/lg 的 height、padding-x、font-size token。
- 新增 `.button-block`:`display: flex; width: 100%`。
- 新增 `.button:disabled`:`cursor: not-allowed`、`opacity` 降低、取消 hover/active 的颜色与缩放效果(需覆盖各 type 的 hover 规则)。
- 新增 `.button-spinner`:固定尺寸(约 14px)、`animation: spin` 旋转,`@media (prefers-reduced-motion: reduce)` 下 `animation: none`。
### tokens.css 扩展
- 在「控件」分组补充:`--fms-control-height-sm: 24px`、`--fms-control-height-lg: 40px`、`--fms-control-padding-x-sm: 8px`、`--fms-control-padding-x-lg: 14px`。
- 在「字体」分组补充:`--fms-font-size-sm: 12px`、`--fms-font-size-lg: 16px`。
- 深色模式 `.dark` 下尺寸 token 与浅色一致,无需重复覆盖。
### App.vue 展示页更新
- 在现有 6 种 type 行下方补充示例分组:禁用态(`disabled`)、加载态(`loading`)、三种尺寸(small/default/large)、通栏(`block`)。
- 保持现有 `.button-row` 布局与卡片容器风格一致。
## 目录结构
```
fms-vue/src/
├── theme/
│ └── tokens.css # [MODIFY] 新增 sm/lg 尺寸与字号 token
├── components/ui/button/
│ ├── button.vue # [MODIFY] 新增 5 个 prop、spinner 模板、aria/disabled 绑定
│ └── index.scss # [MODIFY] 新增 size/block/disabled/loading/spinner 样式
└── App.vue # [MODIFY] 补充禁用、加载、尺寸、通栏示例
```
## 验证方式
- `pnpm dev` 启动后检查:disabled 按钮不可点击且光标为 not-allowed;loading 按钮显示 spinner 且重复点击无效、宽度不跳动;三种尺寸视觉正确;block 按钮占满容器宽度。
- 表单场景验证:`<Button nativeType="submit">` 可正常提交,默认按钮不触发提交。