本文档集顺序:① prod.md(产品与决策)→ ② spec.md(规格)→ ③ task.md(验收)。编写与修订亦建议按此顺序。
侧栏导航(Side Menu)— 产品说明
1. 业务职能与要解决的问题
本组件是**管理后台壳层**的**左侧主导航**:在固定宽度侧栏内展示按业务模块分组的菜单树,并与「已打开的子页签」状态联动,使用户在多模块、多层级入口之间快速跳转;在视口变窄时仍以折叠 / 全宽覆盖等方式保持可用。
要解决的核心问题:
- 树状模块结构(含多级入口):保持当前位置可辨识(选中、父级高亮、已打开页签提示)。
- 菜单可能超高:仍能完整浏览(纵向滚动;在满足宽屏媒体条件时用与侧栏风格一致的自绘滚动条,避免原生条割裂视觉)。
- 大屏与窄屏:展开/收拢侧栏与点击打开子页的时序一致,避免动画未完成就切页。
非目标:子页内容、路由注册、权限与数据请求;本组件只消费宿主传入的树与状态。
主要使用者:登录后使用后台的运营/管理员等。
信息结构(便于与 spec 对齐):
- 一级:业务分组,由 antd
Menu.SubMenu 承载(分组标题即模块名)。
- 分组以内:节点若仍有子列表,则由**自研子菜单层**递归展开(解决部分环境下嵌套
SubMenu 展示异常的问题);无子列表则为叶子,点击打开页。
2. 用户感知(人如何理解这个组件)
可见状态
- 整体:深色竖向导航;顶区为站点/产品标题;下方为可滚动菜单树。
- 一级分组:分组标题;若子树中有当前页,分组须有「子树选中」可辨样式。
- 分组内仍含下级:由自研子菜单层呈现,可展开/收起,箭头随展开在「V 形」与「展开」之间变化;选中落在本节点与选中落在子级时标题强调程度不同(本节点选中时更接近「当前页」色块)。
- 叶子项:类型图标与文案;若对应窗格已在「已打开」列表中,须有与未打开可区分的样式(如右侧小箭头仅在「已打开」时明显出现)。
- 窄屏:侧栏可变为盖住主内容的固定层;展开时可占满可视宽度;可配半透明遮罩,点遮罩收起(拖拽自绘滑块时遮罩语义见 spec §5)。
- 菜单超高:在宽屏媒体下,右侧出现细轨 + 滑块(非系统默认宽条外观);拖拽滑块时整壳层级与遮罩反馈与平时不同。
断点与「固定 / 覆盖」(补充详述)
- 大屏:主导航是左侧固定宽度竖条,主内容在右,菜单不「浮」在整页上。
- 屏变窄:侧栏进入固定覆盖语义;仅当用户展开时才以全宽抽屉压在主内容之上,收起后主内容再占满。
自定义滚动条(宽屏,与 lg 断点同量级 992px)(补充详述)
- 一屏装不下时,在满足宽屏媒体且判定需要滚动后,右侧出现与深色侧栏一致的细条,而非突兀的系统条。
- 指针移入可滚菜单区时滑块先略提亮,再移到滑块热区则变宽、变亮(两级 hover 可感知差异)。
- 拖拽时列表跟手,滑块颜色立刻到位(关闭颜色过渡以免迟滞);若同时存在遮罩层,则近透明且不应误触关闭逻辑。
- 不溢出时右侧无可点死区(轨不接收指针)。
表现行为
- 分组与自研子菜单的展开/收起有过渡(收起与展开时长可略有不同,约 0.2s~0.3s 量级);侧栏与内容区过渡与现网一致(约 0.3s 量级)。
- 自绘轨在需要时渐入(可带 delay);拖拽时关闭颜色过渡以保证跟手。
交互反馈
- 点叶子:大屏立即打开页;窄屏固定覆盖模式下先收侧栏,短延迟后再打开页。
- 点遮罩(非拖拽滚动条、且遮罩为可见半透明时):收起侧栏。
- 拖拽自绘滑块:内容与滑块联动;拖拽中遮罩与层级语义见 spec.md §5。
- resize:重算是否需滚动条与滑块比例。
交互反馈阶梯(自绘滚动条,白话)
从「离滚动条较远」到「正在拖拽」,用户应能感到至少三档:① 菜单区可滚但未对准轨/柄;② 对准轨或滑块热区,轨与滑块明显可交互;③ 按下拖拽,高对比、过渡关闭。详见 spec §5 表格化谓词,便于验收对齐。
3. 操作时序与流程
主路径(打开某叶子功能)
- 在树中找到目标叶子并点击。
- 大屏(非固定覆盖):宿主立即收到「打开页」。
- 窄屏固定覆盖态:先收起侧栏 → 约 300ms 后宿主收到「打开页」。
分支
- 手风琴:同一父级下新开一侧同级则收起其他同级展开(antd 一级
SubMenu 与自研子菜单层两条更新路径写入同一套 openKeys 语义须一致)。
- 只收起不导航:点遮罩等 → 不收新页。
- resize:可能在「要/不要自绘滚动条」「是否进入窄屏固定覆盖」间切换。
顺序约束
- 窄屏下须先收侧栏再打开页(延迟与动画对齐)。
- 展开导致高度变化后,须在动画稍后再检测是否需滚动(避免算错高度);一级菜单与自研层回调后的延迟可略有不同,但均须完成一次可靠检测。
断点与覆盖(典型时序)
- 由宽变窄 → 宿主与内部态随
breakpoint 同步,常呈现收起、主区全宽。
- 用户展开菜单 → 固定覆盖 + 可配遮罩;点遮罩收起。
- 再拉宽 → 恢复左侧固定条与主内容并排。
自定义滚动条(典型时序)
- 列表超高 → 判定需滚动后,轨与滑块延时淡入。
- 移入菜单滚动区 → 滑块先中间强调色。
- 移到滑块热区 → 加宽、高亮。
- 拖拽 → 联动滚动;遮罩按 spec §5;滑块关闭颜色 transition。
- 松开 → 恢复 hover 与过渡。
- 不再溢出 → 轨隐藏且不挡指针,内边距恢复。
4. 产品决策与架构(逻辑与决策一体)
为何需要自研子菜单层(分组内「仍有子列表」)
- 上下文:antd
Menu.SubMenu 嵌套在部分移动端/窄视口下曾有多级展示异常。
- 决策:分组内凡仍有
items 的节点用自研子菜单层(外层列表项 + 内嵌 Menu);一级分组仍用 antd SubMenu。
- 后果:
openKeys 同时服务两套展开来源;迁移 antd v6 须回归多级与触摸。
手风琴式同级展开
- 上下文:纵向空间有限。
- 决策:新展开一项时,从展开集合中移除同级其他 key(基于树结构求同级)。
- 后果:非 antd 默认的「多同级全开记忆」;迁移勿擅自改成全开除非产品要求。
自绘纵向滚动条(宽屏媒体下且内容溢出)
- 上下文:原生条与深色侧栏不协调,且需与箭头、内边距对齐。
- 决策:在宽屏媒体且内容超出可视区(含容差阈值)时自绘轨与滑块,transform 移滑块并与
scrollTop 比例同步;不满足媒体条件时不依赖自绘轨(由布局内滚动或抽屉承担)。
- 后果:resize 与展开后须重算;拖拽与遮罩、z-index 协同见 spec §5。
遮罩
- 上下文:窄屏覆盖需提示「壳外」并可点关;拖拽滚动条时不应误关。
- 决策:窄屏展开时半透明遮罩;拖拽滚动条时遮罩可仍占位但近透明,侧栏容器抬升 z-index 以免挡拖拽。
宿主侧「按页名找页」与深层树(已知边界)
若宿主存在仅在分组下浅层扫描的辅助逻辑,而真实菜单深于两层,可能找不到叶子——须由宿主与数据层保证一致;详见 adr.md 相应条。
5. 对 spec 与 task 的指向
| 内容 |
落点 |
| 树字段、展开/选中/点击顺序 |
spec.md §2–§4 |
根容器语义、断点、Sider、布尔组合 |
spec §3 |
| 遮罩、自绘滚动条、子菜单动效 |
spec §5 |
| 可测条目 |
task.md |
| 历史 ADR 式条目(可选对照) |
adr.md |