7.8 KiB
7.8 KiB
name, overview, design, todos
| name | overview | design | todos | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| spin-component | 实现 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 结构,采用"内容容器 + 绝对定位覆盖层"方案,所有覆盖元素脱离文档流:
<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)- 内部
activeref 为实际显示状态(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-bg0.45 轻,不压暗内容可读性) - 文案用
--fms-text-secondary12px
性能与可靠性
- 无高频事件、无全局监听;动画仅 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
关键代码结构
// 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 正常