AdmSysV2【公共组件库】@前端(For Git Submodule)
edit | blame | history | raw

本文档集顺序:① prod.md → ② 本页 spec → ③ task.md。请先读 prod;验收见 task。

侧栏导航 — 规格说明

1. 概述与范围

本规格描述壳层侧栏的**技术契约**:数据树、受控展开、响应式侧栏、antd Layout.Sider / Menu 的组合,以及分组内多级由**自研子菜单层**承载(现网实现可拆为独立组件,迁移时可替换实现,语义须一致)。业务目标与用户叙事以 prod.md 为准。

  • 依赖:React、antd v6 目标栈下的 Layout.SiderMenu(dark、inline)。
  • 范围:侧栏容器、菜单渲染、遮罩与自绘纵向滚动条;不含路由与子页实现。
  • 非目标:不复述 antd 通用 API 手册;只写与默认不一致或叠加的约定。

写法:以行为、谓词与可验收参数为主,不锁定现网内部 class/state/函数名;实现可重命名,须保持等价语义。下列 antd/React 对外概念(如 openKeysonBreakpoint)保留。


2. 数据模型

菜单树(宿主传入)

  • 顶层为数组;每项为一级分组,由 antd Menu.SubMenu 承载,含:
  • 标识:id(优先)或 key,全树用于选中与展开(与 openKeysselectedKeys 字符串化一致)。
  • 展示名:name(作分组标题)。
  • 子列表:items;其内为二级及以下节点。
  • 分组内节点(任意深度):
  • 若仍有非空 items → 可展开父节点,由自研子菜单层渲染,可递归;
  • 否则为叶子(点击打开页)。

运行态

  • 当前选中键:与某节点标识一致,驱动 selectedKeys(与窗格 key 字符串一致)。
  • 已打开窗格列表:用于叶子「已打开」样式;判定为某窗格 key 与叶子 id 一致(若项目统一用 id/key 之一,须全树一致)。
  • collapsed / title:宿主驱动折叠;顶区文案。

可选:静态配置与接口合并、hiddenPaths、负数 id 等由宿主与数据层约定,侧栏以输入树已最终可用为前提。


3. 布局与响应式

根容器与 Layout.Sider(须可观测)

外层根容器高度随壳层占满;下列语义由内部 state、宿主 collapsedLayout.Sider 的 breakpoint 与拖拽态共同决定(实现可用任意 class,须满足谓词):

语义 谓词(逻辑合取)
窄屏固定覆盖态 Sider 的 breakpoint 已打破(现网为 lg,与 ≥992px 媒体自绘轨大致同量级);内部记录与 onBreakpoint(true) 一致
窄屏且抽屉展开为全宽 窄屏固定覆盖态且宿主 collapsed === false
窄屏且收起不占全宽 窄屏固定覆盖态且 collapsed === true(侧栏收至零宽量级,主内容区占满)
自绘滚动条拖拽中 用户正在拖拽自绘滑块(与 §5 联动);根容器进入「滚动拖拽」语义,z-index 抬升
宽屏侧栏并排 非窄屏固定覆盖态;侧栏为常规并排,不施加「全宽抽屉压在主内容上」

断点联动(顺序与契约):

  1. onBreakpoint(broken) 触发时,须调用 onSetMenuCollapse(broken),并使内部「窄屏固定覆盖」与 broken 同步。
  2. 不得假设仅断点一侧变化:宿主 collapsed 与断点共同决定「全宽展开」是否出现。

用户能感知到什么(断点)

  • 大屏:左侧固定宽度条,主内容在右。
  • 屏变窄:进入固定覆盖语义;不展开时主内容占满。
  • 主动展开才呈现全宽压在主内容之上;收起后再占满。

典型操作时序(断点)

  1. 由宽变窄 → 宿主与内部态随断点同步,常先收起,主区全宽。
  2. 用户展开菜单 → 全宽抽屉 + 遮罩;点遮罩收起。
  3. 再拉宽 → 恢复并排布局。

实现要点(与根容器对照)

  • onBreakpointonSetMenuCollapse(broken) 与内部窄屏态同一布尔。
  • 全宽抽屉仅当窄屏且未 collapsed。
  • 拖拽滚动条时根容器抬升 z-index,遮罩近透明但仍可参与指针路由(见 §5),避免挡滑块。

顶区与可滚内容区

  • 顶区固定高度量级约 50px;宽度与下方菜单区一致,并随滚动条占位宽度加宽(与菜单可滚区同步测量)。
  • 菜单区内容宽度约 210px 量级 + 占位;可视高度 + 容差(现网约 10px)< 内容高度时判定「需要纵向滚动」,驱动宽屏自绘轨显示(§5)。
  • window resize 时重测滚动需求与滑块比例。

4. 交互与状态(逻辑)

openKeys(受控)

  • 两套来源写入同一状态:① antd 一级 MenuonOpenChange(仅作用于一级分组 SubMenu);② 自研子菜单层的展开/收起回调(现网用独立回调名,避免与 Menu 内部拦截冲突)。
  • 同级手风琴:当检测到新展开的 key 时,在树中求同级其他 key,从本次意图集合中剔除同级其他再合并;纯收起则按传入集合更新。
  • 展开后滚动检测:须在动画/布局稳定后再次检测是否需纵向滚动;一级路径与自研路径延迟可不同(现网约 0.35s~0.5s 量级),须各自完成一次 _checkScrolling 等价逻辑,避免滑块高度为 0 或永久不可滚。

选中

  • selectedKeys 与当前选中键字符串形式一致。
  • 一级分组:子孙中有选中 → 子树选中样式(现网为分组标题区可辨强调)。
  • 自研子菜单层:选中在本节点与选中在子级两种标题样式可区分(见 §5)。

点击叶子

  • 非窄屏固定覆盖:立即 onClickMenuItem(item)(载荷为完整 item)。
  • 窄屏固定覆盖态:先 onSetMenuCollapse()(或等价收起),约 300ms 后 onClickMenuItem(item)

自绘滚动条(逻辑)

  • 滑块高度与可视/内容高度成比例;滑块位移与 scrollTop 双向同步;支持鼠标与触摸(按下/移动/结束)。
  • 内容滚动驱动滑块时仅更新位移,不重复写 scrollTop(避免抖动);拖拽时按位移比例写回 scrollTop

5. 自定义样式与动效

用户感知与操作时序全貌见 prod.md §2–§3。本节给状态、时长、层级与参数目标,实现可用任意样式方案,须可验收。

遮罩

项目 约定
可见(半透明) 窄屏且侧栏展开且非拖拽滚动条的典型态;背景透明度目标约 0.2(黑底)
近透明 自绘滚动条拖拽中:背景约完全透明,仍占据全屏命中区时需配合 z-index(见下)避免误点关闭
点击 非拖拽滚动条时点击遮罩 → onSetMenuCollapse()(或等价);拖拽中点击不收拢

层级(目标关系):窄屏下固定覆盖容器整体 z-index 高于主内容;拖拽中侧栏区域须高于近透明遮罩,以免滑块被挡。现网量级:容器拖拽态约 50、遮罩约 10、侧栏内容区约 2(实现可调整,须保持相对关系)。

自绘滚动条(宽屏媒体 + 内容溢出)

出现条件(合取):视口 ≥ 约 992px(与 Siderlg 断点同量级)且判定内容超高(§3 容差规则)且进入「显示轨」状态。

交互反馈阶梯(指针 / 命中域)

阶梯 命中谓词(语义) 视觉与过渡目标
外围上下文 宽屏且溢出,未 hover 可滚菜单区;轨可 opacity 0→1 渐入(轨整体可带 delay,如约 0.3s delay + 0.2s 过渡量级) 轨上滑块「细、深」,低对比
控件邻近带 指针进入可滚菜单区(.c-menu-scroll-show 等价语义),尚未指向滑块主热区 滑块条先变为中间强调色(如灰蓝),宽度可仍为窄条
主操作面 指针落在滑块热区(轨内滑块可拖区域) 滑块加宽(如约 6px→12px)、更亮;background / width 过渡约 0.3s
激活 / 拖拽中 mousedown / touch 拖拽滑块 保持加宽与高亮;background-color 等 transition: 0s;遮罩按上表近透明

不需要滚动时:轨不可见且 pointer-events: none(或等价),不形成右侧死区;菜单区无为轨预留的额外右内边距。

需要滚动时:内容区保留纵向滚动(overflow-y: scroll 语义),右侧内边距(目标约 20px)为轨留位;轨宽约 20px,贴于可滚区右侧;滑块在轨内用 transform: translateY 与 scrollTop 同步。

与 JS 的边界:「是否溢出」「是否宽屏」由检测与媒体查询共同决定;拖拽中由 React state 切换根容器「拖拽」语义并联动遮罩样式。

一级菜单与叶子(深色主题局部)

  • hover / selected 与叶子右侧 Caret 箭头:未打开时常隐藏或极弱,已打开叶子须可见可辨。
  • 一级分组子树选中:分组标题区与默认态可区分。

自研子菜单层

  • 标题区箭头由两段线模拟,展开时旋转可感知。
  • 子列表 max-height:收起向 0、展开向大值过渡;收起与展开 duration 可不同(现网约 0.2s 收起 / 0.3s 展开),缓动可用 antd 常用 cubic-bezier。
  • 选中在本节点:标题背景接近「当前页」强调色;仅有子级选中:标题为弱强调(颜色/字重与上一档可辨)。

可访问性与降级

  • prefers-reduced-motion:产品未强制时可注明「当前不约束」;若实现,应同步缩短或关闭展开与轨渐入。
  • 键盘焦点与自绘轨:当前不强制与原生滚动条等价,但须避免「轨不挡指针」与焦点环逻辑冲突。

6. 与宿主应用的契约

概念 / 常见 prop 名 说明
菜单树 §2
顶区标题 title
collapsed 宿主驱动;与 Sider collapsed 绑定
当前选中键 curActivePaneKeyselectedKeys
已打开列表 panesOnShelf;叶子「已打开」判定见 §2
onSetMenuCollapse 断点传入 boolean;遮罩、窄屏点叶子前等可为无参收起;语义见 §3–§4
onClickMenuItem 叶子;载荷为完整 item;窄屏时序见 §4

7. 验收

验收标准见 task.md