20260816220132
This commit is contained in:
1 parent
b6f9a4c912
commit
72993ecdcd
179 files changed
+20050
-633
No files matched your search
@@ -0,0 +1,172 @@
|
||||
---
|
||||
name: spin-component
|
||||
overview: 实现 Spin 加载组件(形态一:独立指示器;形态二:包裹内容+遮罩,且不破坏内部布局),配套 demo 与注册。
|
||||
design:
|
||||
architecture:
|
||||
framework: vue
|
||||
styleKeywords:
|
||||
- 加载反馈
|
||||
- 轻量遮罩
|
||||
- 居中指示器
|
||||
fontSystem:
|
||||
fontFamily: system-ui
|
||||
heading:
|
||||
size: 14px
|
||||
weight: 500
|
||||
subheading:
|
||||
size: 12px
|
||||
weight: 400
|
||||
body:
|
||||
size: 12px
|
||||
weight: 400
|
||||
colorSystem:
|
||||
primary:
|
||||
- "#0f172b"
|
||||
background:
|
||||
- transparent
|
||||
text:
|
||||
- "#86909c"
|
||||
functional:
|
||||
- "#0f172b"
|
||||
todos:
|
||||
- id: spin-tokens
|
||||
content: 用 [skill:antdv-next] 确认形态二结构,tokens.css 新增 --fms-spin-size
|
||||
status: completed
|
||||
- id: spin-style
|
||||
content: 创建 spin/index.scss(指示器旋转动画 + 形态二容器/轻量遮罩/绝对居中指示器 + reduced-motion)
|
||||
status: completed
|
||||
dependencies:
|
||||
- spin-tokens
|
||||
- id: spin-component
|
||||
content: "创建 spin/spin.vue(spinning/delay/description + #indicator/#description/默认插槽 + delay 定时器清理 + ARIA)"
|
||||
status: completed
|
||||
dependencies:
|
||||
- spin-style
|
||||
- id: spin-demo
|
||||
content: 创建 demo/spin.vue 并注册到 App.vue「反馈」分类与 demoMap
|
||||
status: completed
|
||||
dependencies:
|
||||
- spin-component
|
||||
- id: spin-verify
|
||||
content: 用 [skill:playwright-cli] 实测形态二内部布局零偏移 + oxlint 静态检查并汇报
|
||||
status: completed
|
||||
dependencies:
|
||||
- spin-demo
|
||||
---
|
||||
|
||||
## 用户需求
|
||||
|
||||
实现 Spin 加载中组件,支持两种形态:
|
||||
|
||||
- **形态一(无子元素)**:独立加载指示器,可带文案,如 `<Spin spinning description="加载中" />`
|
||||
- **形态二(有子元素)**:包裹内容并覆盖半透明遮罩,如 `<Spin :spinning="loading"><表格/></Spin>`
|
||||
|
||||
**重点要求**:形态二必须做好——不能因为添加 Spin 导致内部元素位置/尺寸错乱。遮罩和指示器应绝对定位脱离文档流,内容容器只加 `position: relative`,加载时内容降透明并禁用交互,布局保持不变。
|
||||
|
||||
## 核心功能
|
||||
|
||||
- `spinning`(Boolean,默认 true):是否加载中
|
||||
- `delay`(Number,默认 0):延迟显示(毫秒),防短请求闪烁,卸载时清理定时器
|
||||
- `description`(String):加载文案,显示在指示器下方
|
||||
- 插槽:`#indicator` 自定义指示器(默认 LoaderCircle 旋转)、`#description` 自定义文案、默认插槽(传入则启用形态二)
|
||||
- 形态二:内容容器加载时 `opacity` 降低 + `pointer-events: none` 禁交互 + 轻量遮罩;指示器与文案绝对居中
|
||||
- ARIA:容器 `aria-busy`、指示器 `role="status"` + `aria-label="加载中"`
|
||||
- 不提供 size 枚举(遵循开发规范 7.1)
|
||||
|
||||
## 技术栈
|
||||
|
||||
- Vue 3 `<script setup>` + scoped SCSS(`@use './index.scss'`)
|
||||
- 设计 token:`src/theme/tokens.css` 新增 `--fms-spin-size`
|
||||
- 图标:`@lucide/vue` 按需导入 `LoaderCircle`(与 Select 加载态一致)
|
||||
- 动画:`@keyframes spin` 旋转 800ms linear infinite(对齐 Button 的 `button-spin`),`prefers-reduced-motion` 停动画
|
||||
|
||||
## 实现方案
|
||||
|
||||
### 形态二布局防错乱(核心)
|
||||
|
||||
参考 antdv-next Spin 结构,采用"内容容器 + 绝对定位覆盖层"方案,所有覆盖元素脱离文档流:
|
||||
|
||||
```text
|
||||
<div class="spin"> ← 仅形态二;position: relative(不改变内部布局)
|
||||
<div class="spin-container"> ← 包裹 children,只加 position: relative
|
||||
<slot /> ← 内部元素位置/尺寸完全不受影响
|
||||
</div>
|
||||
<div v-if="spinning" class="spin-mask" /> ← 绝对定位 inset:0,轻量半透明遮罩
|
||||
<div v-if="spinning" class="spin-section"> ← 绝对定位 50%/50% translate(-50%,-50%) 居中
|
||||
<LoaderCircle class="spin-indicator" /> ← 或 #indicator 插槽
|
||||
<div class="spin-description">加载中</div> ← 或 #description 插槽
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
关键决策:
|
||||
|
||||
- 遮罩与指示器全部 `position: absolute`,不占文档流 → 内部元素位置不会偏移
|
||||
- `.spin-container` 不加任何尺寸/布局属性,只做 `position: relative` 承载遮罩层 → 内部布局零影响
|
||||
- 加载时容器 `opacity: 0.5; user-select: none; pointer-events: none`(对齐 antdv),遮罩 `z-index` 高于容器、低于指示器
|
||||
- 形态一(无默认插槽)渲染为 `inline-flex` 指示器区,不产生包裹层
|
||||
|
||||
### Props 与状态
|
||||
|
||||
- `spinning` 默认 true;`delay` 用 `setTimeout` 延迟内部显示,`watch` + `onBeforeUnmount` 清理定时器(规范 4.3)
|
||||
- 内部 `active` ref 为实际显示状态(delay 生效后),模板基于 `active` 渲染
|
||||
|
||||
### 样式与 token
|
||||
|
||||
- `--fms-spin-size: 20px` 加入 tokens.css `:root`(尺寸不随主题)
|
||||
- 指示器颜色 `var(--fms-primary)`;遮罩用 `color-mix(in srgb, var(--fms-text) 6%, transparent)` 派生轻量色(比 Modal 的 `--fms-mask-bg` 0.45 轻,不压暗内容可读性)
|
||||
- 文案用 `--fms-text-secondary` 12px
|
||||
|
||||
### 性能与可靠性
|
||||
|
||||
- 无高频事件、无全局监听;动画仅 transform(低成本),reduced-motion 关闭
|
||||
- `delay` 定时器在卸载与 spinning 翻转时清理,避免内存泄漏
|
||||
- 遮罩层拦截点击(pointer-events 由容器 none、遮罩 auto 恢复),防止加载中误操作
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
fms-vue/src/
|
||||
├── theme/
|
||||
│ └── tokens.css # [MODIFY] 新增 --fms-spin-size: 20px
|
||||
├── components/ui/
|
||||
│ ├── spin/
|
||||
│ │ ├── spin.vue # [NEW] 主组件:spinning/delay/description + #indicator/#description/默认插槽;形态一/二分支;delay 定时器清理;ARIA
|
||||
│ │ └── index.scss # [NEW] 指示器旋转动画、形态二容器/遮罩/居中指示器、reduced-motion
|
||||
│ └── demo/
|
||||
│ └── spin.vue # [NEW] 演示:基础指示器/带文案/包裹内容遮罩(重点验证内部布局不偏移)/delay 防闪烁/自定义 indicator
|
||||
└── App.vue # [MODIFY] 「反馈」分类注册 Spin + demoMap
|
||||
```
|
||||
|
||||
## 关键代码结构
|
||||
|
||||
```js
|
||||
// spin.vue props
|
||||
defineProps({
|
||||
spinning: { type: Boolean, default: true },
|
||||
delay: { type: Number, default: 0 },
|
||||
description: { type: String, default: '' },
|
||||
})
|
||||
// 内部 active 状态:delay 后置 true;watch(spinning/delay) + onBeforeUnmount 清理 setTimeout
|
||||
// 模板:hasDefaultSlot ? 形态二(container+mask+section 绝对定位) : 形态一(inline-flex section)
|
||||
```
|
||||
|
||||
## 设计说明
|
||||
|
||||
Spin 为反馈类加载组件,视觉遵循项目现有加载态语言(Button/Select 的旋转 Loader 图标):
|
||||
|
||||
- **指示器**:`LoaderCircle` 图标 20px(`--fms-spin-size`),主色 `--fms-primary`,800ms 匀速旋转;文案 12px 次级灰 `--fms-text-secondary`,指示器与文案垂直排列、居中
|
||||
- **形态一**:inline-flex 水平/垂直居中的指示器区,可独立嵌入按钮、卡片等任意容器
|
||||
- **形态二**:内容保持原布局不变,加载时内容降透明(opacity 0.5)并禁用交互;轻量遮罩(文字色 6% 混合)覆盖内容区,指示器+文案绝对居中于遮罩之上,形成"内容不可操作、加载居中"的视觉反馈
|
||||
- 支持 `prefers-reduced-motion`:动画关闭,仅静态指示器
|
||||
|
||||
## Agent Extensions
|
||||
|
||||
### Skill
|
||||
|
||||
- **antdv-next**
|
||||
- Purpose: 确认 Spin 形态二(包裹内容 + 遮罩)的 DOM 结构与交互细节(延迟显示、遮罩层级、指示器居中),确保方案与参考库一致
|
||||
- Expected outcome: 形态二实现不破坏内部布局的准确依据
|
||||
- **playwright-cli**
|
||||
- Purpose: 在 dev server(5082)上实测 Spin demo,重点验证形态二包裹内容后内部元素位置/尺寸与未包裹时一致
|
||||
- Expected outcome: 实测通过:指示器旋转、遮罩覆盖、内部布局零偏移、delay 生效、自定义 indicator 正常
|
||||
Reference in new issue
Block a user