107 lines
5.8 KiB
JSON
107 lines
5.8 KiB
JSON
{
|
||
"slug": "sidemenu",
|
||
"end": "react",
|
||
"curated": true,
|
||
"summary": "左侧导航菜单:items 给条目树、activeKey 定选中,选中变化经 onChange 回传 key。",
|
||
"usage": [
|
||
"React 端这是族模板生成的实现:文件头注明 @generated 与重跑命令,本组件的族参数是 direction=side(SideMenu.jsx:4-12)。",
|
||
"条目数据支持 icon、badge、children、disabled 五个字段,分别渲染为图标、角标、子菜单与禁用态(SideMenu.jsx:54-60)。",
|
||
"选中状态有两个来源:activeKey 只在挂载时写入内部 active(useState 初值),之后点击走 onChange 通知父级(SideMenu.jsx:15,30-31)。",
|
||
"点击父级项不选中也不回调,只切换子菜单开合;父级自身展开态由 open 单独维护(SideMenu.jsx:25-28)。",
|
||
"父项的高亮是派生值:只要任一子项等于 active,父项就算激活(isTopActive)(SideMenu.jsx:21)。",
|
||
"选中结果只覆盖叶子:有 children 的条目在 onChange 之前就 return 了(SideMenu.jsx:25-29)。"
|
||
],
|
||
"bestPractices": [
|
||
"activeKey 是初始值语义,运行期切换不会同步进组件;受控选择需在 onChange 里更新父状态并靠父组件重渲染表现(SideMenu.jsx:15)。",
|
||
"点击父级不会触发 onChange,父级项不要当作可选菜单项用,否则用户会认为点击无效。",
|
||
"条目 key 必须唯一且与 activeKey 取值一致,isTopActive 与 is-active 都靠严格相等比较。"
|
||
],
|
||
"apiCarrier": {
|
||
"kind": "props",
|
||
"note": "React 端的 API 载体是 props 与回调:属性驱动外观(type/size/disabled 等布尔与枚举),交互经 onXxx 回传(如 onChange/onClick/onSelectionChange);没有 v-model,受控组件固定写成 value + onChange,非受控则用 defaultValue。",
|
||
"table": [
|
||
{
|
||
"name": "items",
|
||
"type": "Array<{ key, label, icon?, badge?, disabled?, children? }>",
|
||
"desc": "菜单条目树"
|
||
},
|
||
{
|
||
"name": "activeKey",
|
||
"type": "string",
|
||
"desc": "初始选中 key,仅首次挂载读取"
|
||
},
|
||
{
|
||
"name": "onChange",
|
||
"type": "(key) => void",
|
||
"desc": "点击叶子条目时回调 key"
|
||
},
|
||
{
|
||
"name": "key",
|
||
"type": "string",
|
||
"desc": "条目唯一标识,来自 items[*] 字段而非组件 props"
|
||
},
|
||
{
|
||
"name": "label",
|
||
"type": "string",
|
||
"desc": "条目文案,来自 items[*] 字段而非组件 props"
|
||
},
|
||
{
|
||
"name": "icon",
|
||
"type": "string",
|
||
"desc": "条目图标字符,来自 items[*] 字段而非组件 props"
|
||
},
|
||
{
|
||
"name": "badge",
|
||
"type": "string",
|
||
"desc": "条目角标文本,来自 items[*] 字段而非组件 props"
|
||
},
|
||
{
|
||
"name": "disabled",
|
||
"type": "boolean",
|
||
"desc": "条目禁用,来自 items[*] 字段而非组件 props,点击直接返回"
|
||
},
|
||
{
|
||
"name": "children",
|
||
"type": "Array",
|
||
"desc": "子条目,存在时点击仅切换展开"
|
||
}
|
||
]
|
||
},
|
||
"a11y": [
|
||
"根节点是 <nav aria-label=\"主菜单\">(SideMenu.jsx:89-93),并被读到为导航地标。",
|
||
"条目带 role=\"menuitem\" 与 tabIndex={0}、aria-expanded(仅对有子项的条目)(SideMenu.jsx:45-47),是可聚焦的菜单项语义。",
|
||
"只有 tabIndex 而没有方向键处理,键盘可聚焦但需 Tab 逐个走;另外 role=\"menuitem\" 脱离了 menu 容器的上下文,读屏播报可能不完整。"
|
||
],
|
||
"resources": [
|
||
{
|
||
"file": "frameworks/SideMenu.jsx",
|
||
"kind": "React(React)",
|
||
"desc": "React 端组件实现源码,props 与回调的唯一定义处"
|
||
},
|
||
{
|
||
"file": "frameworks/SideMenu.css",
|
||
"kind": "样式",
|
||
"desc": "该 React 实现依赖的样式文件"
|
||
}
|
||
],
|
||
"exampleIds": [
|
||
"sidemenu-ex-1",
|
||
"sidemenu-ex-2",
|
||
"sidemenu-ex-3"
|
||
],
|
||
"notes": [
|
||
"frameworks/SideMenu.jsx:14 中可指到 items(Array<{ key, label, icon?, badge?, disabled?, children? }>)——菜单条目树",
|
||
"frameworks/SideMenu.jsx:14 中可指到 activeKey(string)——初始选中 key,仅首次挂载读取",
|
||
"frameworks/SideMenu.jsx:14 中可指到 onChange((key) => void)——点击叶子条目时回调 key",
|
||
"frameworks/SideMenu.jsx:21 中可指到 key(string)——条目唯一标识,来自 items[*] 字段而非组件 props",
|
||
"frameworks/SideMenu.jsx:55 中可指到 label(string)——条目文案,来自 items[*] 字段而非组件 props",
|
||
"frameworks/SideMenu.jsx:54 中可指到 icon(string)——条目图标字符,来自 items[*] 字段而非组件 props",
|
||
"frameworks/SideMenu.jsx:56 中可指到 badge(string)——条目角标文本,来自 items[*] 字段而非组件 props",
|
||
"frameworks/SideMenu.jsx:24 中可指到 disabled(boolean)——条目禁用,来自 items[*] 字段而非组件 props,点击直接返回",
|
||
"frameworks/SideMenu.jsx:21 中可指到 children(Array)——子条目,存在时点击仅切换展开",
|
||
"props 解构清单见 frameworks/SideMenu.jsx:14-14;本文件 table 只列该端真正消费的属性与回调。",
|
||
"过滤口径:事实包 consumedApi 里还包含绑在组件内部节点上的同名处理器(如 onClick/onChange 绑在内部 button、input、checkbox 上,见 frameworks/SideMenu.jsx 全文),它们不是对外 props,因此未进 table。",
|
||
"table 构成核验:9 行中 3 行是 frameworks/SideMenu.jsx 解构出的顶层 props(解构块 frameworks/SideMenu.jsx:14-14);另 6 行不是顶层 props,而是 frameworks/SideMenu.jsx 内部 state 或 items[*] 数据字段,desc 已逐行标明其来源(组件不接收这些名字作为 prop)。"
|
||
]
|
||
}
|