100 lines
6.0 KiB
Markdown
100 lines
6.0 KiB
Markdown
---
|
||
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">` 可正常提交,默认按钮不触发提交。 |