4.5 KiB
4.5 KiB
Hover 提示统一经验
更新日期:2026-04-30
背景
项目已经提取了共享 hover 提示组件,但应用 UI 中仍散落着原生 title、data-tooltip、局部 CSS tooltip 和直接使用 TDesign Tooltip 的写法。
这类分散实现会导致样式、延迟、层级、可访问性和测试行为不一致,也容易在新功能里继续扩散。
需求边界
本次统一的是“应用 UI 的视觉 hover 提示”,不是机械删除所有 title。
需要统一:
- 按钮、图标、菜单、工具栏、状态徽章、素材库、AI 输入栏、属性面板等应用 UI hover 文案。
- 原生 DOM
title、data-tooltip、局部 CSS tips。 - 组件层直接引入
tdesign-react的Tooltip。 ToolButton title的新增使用。
暂不统一:
- Markdown/用户内容渲染出来的链接、图片语义
title。 - TDesign 表单
tips,它是静态说明文案,不是 hover 提示。
组件规则
- 简短纯文本提示使用
HoverTip。 - 富内容、需要鼠标停留或可交互内容的 hover 浮层使用
HoverCard。 ToolButton title只作为兼容入口保留,新代码使用tooltip。- 共享封装内部可以使用 TDesign
Tooltip,业务组件不要直接引入。 - 测试容易 mock
../shared聚合导出时,优先从../shared/hover引入HoverTip,减少 mock 破坏面。
迁移模式
DOM title
<HoverTip content="上传图片" showArrow={false}>
<button onClick={handleUpload}>
<ImageUploadIcon />
</button>
</HoverTip>
ToolButton
<ToolButton
type="icon"
icon={<DownloadIcon />}
aria-label="下载"
tooltip="下载"
/>
条件提示
<HoverTip content={model.id} disabled={!showIdTooltip} showArrow={false}>
<div role="option">{model.label}</div>
</HoverTip>
守卫脚本经验
不要只靠简单正则扫描 JSX。
onClick={() => ...} 这类属性里包含 >,如果用 <button[^>]*title= 会在箭头函数处提前截断,漏掉后面的 title。
更稳的做法:
- 扫描 JSX opening tag 时记录
{}深度。 - 同时处理字符串引号和模板字符串。
- 找到真正的 tag 结束
>后再判断属性。 - 用脚本所在 package 根目录作为路径基准,避免从仓库根和 package 目录执行时例外路径不一致。
检查脚本应覆盖:
src/componentssrc/tools*.ts*.tsx*.scss*.css
明确允许共享封装和 Markdown 用户内容例外,其他例外必须写进脚本,不要靠口头约定。
性能注意
高频网格路径要特别小心,例如素材库图片卡片、缩略图列表、颜色块列表。
规则:
- 不要在一个高密度列表项里叠多层 hover 浮层。
- 非关键提示优先用可见短文案或静态省略展示。
- hover 样式不要触发布局变化。
- 避免在列表 hover 上使用大阴影、
backdrop-filter或频繁 portal 定位。
如果产品必须在高频网格上保留提示,优先只给关键操作加 HoverTip,不要给每个子元素都加。
Lint 接入经验
drawnix lint 原先直接 eslint .,会扫进 node_modules 里的第三方 .eslintrc,导致无关失败。
更合理的命令:
- ESLint 只扫项目源码目录。
- hover 守卫脚本独立执行。
- 即使 ESLint 被既有基线挡住,也要继续执行 hover 守卫脚本,避免新规则失效。
同时,由于项目把 tdesign-react 映射到本地样式聚合入口,需要在 Nx module boundary 规则中允许 tdesign-react 虚拟入口,否则 ESLint 可能尝试把它当内部路径重写并崩溃。
验证清单
openspec validate refactor-hover-tip-unification --strictpnpm --dir packages/drawnix exec node scripts/check-hover-usage.mjspnpm --dir packages/drawnix exec vitest run src/components/shared/hover/hover-utils.test.tsxpnpm nx typecheck drawnixpnpm nx lint drawnix
如果 pnpm nx lint drawnix 被既有 ESLint 基线阻塞,需要在结果里明确区分:
- hover 守卫是否通过
- typecheck 是否通过
- lint 失败是否来自本次改动
修复检查清单
- 应用 UI 不再直接使用原生 hover
title。 - 应用 UI 不再使用
data-tooltip或局部 CSS tooltip。 - 业务组件不直接从
tdesign-react引入Tooltip。 ToolButton新用法使用tooltip,不是title。- Markdown/用户内容
title例外写进守卫脚本。 - TDesign 表单
tips不按 hover 处理。 - 守卫脚本从仓库根和
packages/drawnix目录执行都能得到一致结果。