9.2 KiB
9.2 KiB
name, overview, todos
| name | overview | todos | |||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| select-tooltip-components | 基于已完成的 Popover 基座派生两个组件:Tooltip(hover 文本提示薄封装)与 Select(基础单选下拉,options prop + 默认插槽双数据源,含 clearable、键盘导航、浮层宽度跟随),并在 App.vue 增补演示。 |
|
产品概述
基于已完成的 Popover 浮层基座,新增两个基础组件并接入组件库演示页:
- Select 下拉选择:基础单选版本,提供与 Input 一致的框体视觉、下拉选项列表、键盘导航、清除与禁用能力,浮层宽度跟随触发器。
- Tooltip 文字提示:Popover 的 hover 薄封装,提供纯文本提示与富内容插槽两种用法。
核心功能
Select 单选下拉
- 基础单选:选中值高亮显示,点击选项选中后自动收起浮层
- 数据源双形态:
options数组 prop([{ label, value, disabled }])渲染标准选项;未传options时渲染默认插槽自定义内容 - 触发器框体:显示选中项文案或 placeholder,右侧 ChevronDown 图标随开合旋转
clearable:有值且悬停/聚焦时显示清除按钮,点击清空disabled:整组件禁用,不响应交互- 键盘导航:上下方向键移动高亮(跳过禁用项)、Enter 确认选中、Esc 关闭浮层
- 浮层宽度跟随触发器宽度,超长选项自动换行,列表超高滚动
Tooltip 文字提示
- hover 触发显示,移入浮层不关闭,移出延迟关闭
contentprop 纯文本提示为主用法,#content插槽承载富内容(插槽优先)- 支持 12 方位、箭头开关、进入/离开延迟、禁用态、受控/非受控
两个组件均沿用现有设计 token(卡片、边框、主色、圆角、字号),保持组件库视觉一致。
Tech Stack
- 前端框架:Vue 3(
<script setup>+ Composition API) - 样式:SCSS + CSS 变量(沿用现有 design tokens)
- 图标:
@lucide/vue - 基座复用:现有
Popover组件与utils/position.js定位纯函数,不改动
Implementation Approach
总体策略
不引入第三方依赖、不新增架构模式。Tooltip 与 Select 均作为 Popover 的派生组件,通过插槽透传复用 Popover 的定位、Teleport、Transition、click outside 与 Esc 关闭能力;各自只负责自身语义、交互和视觉。
- Tooltip:固定
trigger="hover"的薄封装,默认插槽映射为 Popover 的#trigger,内容由contentprop 或#content插槽提供,转发 Popover 相关 props/emits。 - Select:内部组合 Popover(
trigger="click"、placement="bottom-start"、arrow=false、offset=4),自建触发器框体与下拉列表,管理选中值、键盘高亮与浮层宽度跟随。
关键技术决策
- 受控打开状态:Select 内部维护
openRef,通过v-model:open绑定 Popover 实现受控,并在openChange时重置键盘高亮索引。避免在 Select 内重复实现开合逻辑。 - 双数据源:
optionsprop 存在时渲染标准选项列表(含选中/禁用/键盘逻辑);未传时渲染默认插槽(自定义内容逃生舱,由调用方控制关闭)。符合"基础单选、保持精简"的要求。 - 浮层宽度跟随:Popover 定位基于 trigger 尺寸,但浮层 Teleport 到 body 无法继承 CSS 宽度。Select 在打开时测量
.select-trigger的offsetWidth,以min-width内联样式注入.select-dropdown,实现宽度跟随且允许内容自适应扩展。 - 键盘导航:下拉容器设
tabindex="-1",打开时nextTick聚焦以接收键盘事件;ArrowUp/ArrowDown 循环移动activeIndex(跳过 disabled),Enter 选中,Esc 交由 Popover 的 document 监听统一关闭,避免双重处理。 - 清除按钮事件隔离:清除按钮
@click.stop阻止冒泡,避免触发 Popover 的 toggle 开合。
性能与可靠性
- 复用 Popover 的 rAF 合帧滚动跟随,Select/Tooltip 不新增全局监听器。
options查找选中文案使用computed缓存;选项列表渲染无 N+1。- 键盘高亮仅更新
activeIndex状态,选项使用mouseenter同步高亮,避免高频重排。
Implementation Notes
- Popover 透传约定:Popover 的
openprop 默认undefined表示非受控;Tooltip/Select 的受控透传必须保持undefined语义,不能默认false(否则破坏 Popover 非受控回退逻辑)。 - Tooltip 语义:Popover 的
contentRole已按trigger === 'hover'返回'tooltip',Tooltip 固定 hover 即自动获得正确 ARIA role,无需额外处理。 - Select 插槽渲染位置:
<slot name="default" />必须放在 Popover#content的.select-dropdown内部,且仅当options未提供时渲染;useSlots().default用于判断插槽是否存在。 - scoped 样式边界:Tooltip/Select 的浮层内容通过 slot 进入 Popover 的 Teleport 子树,自身 scoped 样式可作用于 slot 内容(Vue 会打上父级 scope id),但不要用 Tooltip 的 scss 覆盖 Popover 的
.popover-content(需:deep且易耦合),浮层基础样式统一由 Popover 提供。 - 验证命令:用
pnpm exec oxlint <files>与pnpm exec oxfmt --check <files>针对性检查源文件;全项目pnpm lint会误报dist-verify构建产物,pnpm build会被批量删除安全拦截,均属环境限制,以 dev server 验证为准。 - 清理:验证后关闭 dev server 与浏览器,删除临时截图/snapshot/日志文件。
Architecture Design
两个新组件与既有基座为单向依赖的派生关系,不修改 Popover 与定位模块:
graph TD
Tooltip[Tooltip 薄封装] -->|trigger=hover| Popover[Popover 基座]
Select[Select 单选下拉] -->|trigger=click bottom-start arrow=false| Popover
Popover --> Position[utils/position.js 定位纯函数]
Select --> Tokens[tokens.css 设计变量]
Popover --> Tokens
- Tooltip:仅做 props/emits 转发与插槽映射,无内部状态。
- Select:内部状态含
openRef(开合)、activeIndex(键盘高亮)、dropdownMinWidth(宽度跟随);计算属性含normalizedOptions(选项规范化)、selectedLabel(选中文案)、hasValue。
Directory Structure
fms-vue/src/
├── theme/
│ └── tokens.css # [MODIFY] 新增 --fms-select-dropdown-max-height(浅色定义,尺寸不随主题变化)
├── components/ui/
│ ├── tooltip/
│ │ ├── tooltip.vue # [NEW] Tooltip 组件:Popover hover 薄封装,content prop + #content 插槽 + 默认插槽触发器
│ │ └── index.scss # [NEW] Tooltip 微调样式:文本换行/行高,浮层基础样式复用 Popover
│ └── select/
│ ├── select.vue # [NEW] Select 组件:触发器框体 + 下拉选项列表 + 键盘导航 + clearable + 宽度跟随
│ └── index.scss # [NEW] Select 样式:触发器/箭头/清除按钮/下拉列表/选项选中/禁用/高亮态
└── App.vue # [MODIFY] 导入组件、导航分类接入(Select→数据录入,Tooltip→反馈)、新增演示 section 与示例状态/样式
Key Code Structures
Select 的核心接口契约(双数据源、单选、clearable、键盘导航依赖此定义):
// select.vue 核心 props / emits
defineProps({
/** 双向绑定的选中值 */
modelValue: { type: [String, Number], default: undefined },
/** 选项数组,存在时渲染标准选项列表;未传则渲染默认插槽 */
options: { type: Array, default: undefined }, // [{ label, value, disabled }]
placeholder: { type: String, default: '请选择' },
disabled: { type: Boolean, default: false },
clearable: { type: Boolean, default: false },
})
defineEmits(['update:modelValue', 'change']) // change 参数为 (value, option)
Agent Extensions
Skill
- antdv-next
- 用途:查询 Antdv Next 中 Select 与 Tooltip 的标准 props/events/slots、键盘导航与浮层宽度跟随实现细节,作为 API 设计与交互参考
- 预期结果:确认 Select/Tooltip 的关键接口命名与交互约定,确保派生组件 API 与成熟组件库对齐
- playwright-cli
- 用途:启动 vite dev server 后自动化验证 Select/Tooltip 的渲染效果与交互(打开/选中/清除/禁用/键盘导航/宽度跟随/受控开合)
- 预期结果:通过截图与坐标/elementFromPoint 测量确认功能正确、无定位偏移,验证后清理临时文件