尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Carbon React 的 UI Shell 组件体系全解析:用 Header、SideNav 与 Switcher 搭建产品外壳

Carbon React 的 UI Shell 组件体系全解析:用 Header、SideNav 与 Switcher 搭建产品外壳 Carbon React 的 UI Shell 组件体系全解析用 Header、SideNav 与 Switcher 搭建产品外壳【免费下载链接】carbonA design system built by IBM项目地址: https://gitcode.com/GitHub_Trending/carbo/carbonUI Shell 是 IBM Carbon Design System 中用于构建产品外壳product shell的一组 React 组件集合它承载应用最顶层的导航框架顶栏Header、侧边导航SideNav以及右侧面板RightPanel / HeaderPanel中的产品切换器Switcher。本篇文章以 packages/react/src/components/UIShell/README.md 为骨架逐层拆解每一个组件的职责、Props、组合关系与底层实现并结合仓库源码给出可直接复制的实战示例帮助你快速为 Carbon 应用搭建符合 IBM 设计规范的一体化导航壳。UI Shell 在 Carbon 中的定位在 Carbon 的官方设计语境中Shell 承担的角色类似 macOS 顶部的 Apple 菜单、全局系统控件以及底部/侧边 Dock它把整个产品组合portfolio的导航统一收纳起来让用户在任意页面都能快速定位并切换位置。Carbon 的 UI Shell 结构大致可分为三大区域Header顶栏应用最顶部的横条包含菜单按钮、产品名、导航链接与全局操作搜索、通知、应用切换等SideNav侧边导航位于顶栏下方或随顶栏联动的次级导航容器可固定宽度或灵活展开RightPanel / HeaderPanel右侧面板配合全局操作弹出的抽屉式面板常用于承载应用切换器Switcher。在代码层面所有这些组件都由 packages/react/src/index.ts 通过export * from ./components/UIShell统一导出你可以直接从carbon/react包中引入。组件总览UI Shell 的完整家族树根据 README 的组件清单UI Shell 由三个顶级容器及其子组件构成。下面用一棵组件树展示其完整结构圆括号内为该组件的核心职责Header应用顶栏 ├── HeaderMenuButton菜单展开/收起触发按钮 ├── HeaderName产品名称如 IBM [Product] ├── HeaderGlobalBar全局操作容器 │ └── HeaderGlobalAction单个全局操作如搜索/通知图标按钮 └── HeaderNavigation顶栏导航区 ├── HeaderMenu可展开的导航子菜单 └── HeaderMenuItem导航菜单项通常是链接 SideNav页面侧边导航容器 ├── SideNavHeader侧边导航顶部区域 │ └── SideNavDetails侧边导航标题 │ └── SideNavSwitcher顶层的可选项切换下拉框 ├── SideNavItems子导航项容器 │ ├── SideNavLink侧边导航中的链接 │ └── SideNavMenu可折叠的分组菜单 │ └── SideNavMenuItem分组菜单内的链接 RightPanel / HeaderPanel右侧面板容器 └── Switcher面板内的产品链接列表 ├── SwitcherItem列表项通常是链接 └── SwitcherDivider列表项之间的分隔线此外UI Shell 还提供了几个在 README 之外但同样由 index.ts 导出的配套组件Content页面主内容容器、SkipToContent无障碍跳过导航链接、HeaderContainer顶栏与侧边导航联动状态管理、HeaderSideNavItems把 Header 菜单项复用到 SideNav 中等。Header 顶栏家族逐组件拆解Header 家族全部以header语义元素渲染由 Header.tsx 定义其内部通过usePrefix生成cds--header类名并透传aria-label/aria-labelledby方便屏幕阅读器识别整个导航区。HeaderMenuButton顶栏最左侧的汉堡按钮HeaderMenuButton.tsx 渲染一个button typebutton默认图标来自carbon/icons-react的Menu与Close。它支持的 Props 包括isActive为true时显示关闭Close图标用于表示侧边导航当前处于展开状态isCollapsible为false时按钮会被加--header__menu-toggle__hidden类而隐藏用于不需要展开/收起交互的场景renderMenuIcon/renderCloseIcon自定义展开与收起图标aria-label既作为无障碍标签也会被写入title属性。HeaderMenuButton aria-label{isSideNavExpanded ? Close menu : Open menu} onClick{onClickSideNavExpand} isActive{isSideNavExpanded} aria-expanded{isSideNavExpanded} /HeaderName展示产品名称HeaderName.tsx 渲染一个链接默认prefix为IBM会在产品名前渲染前缀与空格形成 IBM [Platform Name] 的经典样式HeaderName href/ prefixIBM My Product /HeaderName如果不想显示前缀将prefix传为空字符串即可。它底层复用 Link.tsx因此也支持as多态替换为 React Router 的Link等自定义元素。HeaderGlobalBar 与 HeaderGlobalAction全局操作区HeaderGlobalBar.tsx 是一个纯容器cds--header__global用于包裹多个HeaderGlobalAction。而 HeaderGlobalAction.tsx 本质是一个特殊的图标按钮——它基于Button组件并固定使用hasIconOnly、sizelg、kindghost、tooltipPositionbottom同时额外支持isActive激活态例如通知面板打开时高亮tooltipAlignmenttooltip 对齐方式取值start | center | endtooltipHighContrast默认true使用高对比度 tooltip 主题tooltipDropShadow是否给 tooltip 加投影注意children应传入一个图标组件。HeaderGlobalBar HeaderGlobalAction aria-labelSearch onClick{handleSearch} Search size{20} / /HeaderGlobalAction HeaderGlobalAction aria-labelNotifications onClick{handleNotify} Notification size{20} / /HeaderGlobalAction /HeaderGlobalBarHeaderNavigation / HeaderMenu / HeaderMenuItem顶栏导航HeaderNavigation.tsx 渲染navul classcds--header__menu-bar作为导航链接与子菜单的容器HeaderMenuItem.tsx 渲染单个菜单链接支持isActive高亮当前页配合aria-currentpage与多态asHeaderMenu.tsx 渲染可展开的下拉菜单menuLinkName必填菜单标题文字children应传入一系列HeaderMenuItemisActive激活整个菜单isCurrentPage为已弃用别名源码中用deprecate标记renderMenuContent自定义菜单标题右侧内容默认是ChevronDown箭头。从 HeaderMenu.tsx 的实现可以看到完整的无障碍交互触发元素带aria-haspopupmenu与aria-expanded按 Enter/Space 切换展开、按 Escape 关闭并把焦点还给菜单按钮失焦到菜单外部时自动收起所有子项tabIndex被设为 -1由组件统一管理焦点避免 Tab 键经过大量菜单项。HeaderNavigation aria-labelIBM [Platform] HeaderMenuItem href/Link 1/HeaderMenuItem HeaderMenu menuLinkNameLink 4 aria-labelLink 4 HeaderMenuItem href/sub-1Sub-link 1/HeaderMenuItem HeaderMenuItem isActive href/sub-2Sub-link 2/HeaderMenuItem /HeaderMenu /HeaderNavigationHeaderContainer顶栏与侧边导航的联动状态HeaderContainer.tsx 采用render prop模式统一管理顶栏菜单按钮与 SideNav 的展开/收起状态其render函数会收到两个参数isSideNavExpanded当前侧边导航是否展开onClickSideNavExpand切换展开状态的回调。同时它监听了全局Escape键按下时自动收起侧边导航源码位于 HeaderContainer.tsx。如果不想引入额外状态管理直接使用HeaderContainer是最省心的方式HeaderContainer render{({ isSideNavExpanded, onClickSideNavExpand }) ( Header aria-labelPlatform SkipToContent / HeaderMenuButton aria-label{isSideNavExpanded ? Close menu : Open menu} onClick{onClickSideNavExpand} isActive{isSideNavExpanded} aria-expanded{isSideNavExpanded} / HeaderName href/ prefixIBM Platform /HeaderName SideNav aria-labelSide navigation expanded{isSideNavExpanded} isPersistent{false} onSideNavBlur{onClickSideNavExpand} SideNavItems{/* ... */}/SideNavItems /SideNav /Header )} /SideNav 侧边导航家族容器、标题与菜单SideNav是页面级次级导航的容器源码位于 SideNav.tsx它通过forwardRef暴露 DOM 节点并支持大量配置项是 UI Shell 中最灵活的组件之一。SideNav 的关键 Props 与受控/非受控模式expanded传入该 prop 后 SideNav 变为受控组件源码通过expandedProp ! undefined判定见 SideNav.tsxdefaultExpanded非受控模式下的初始展开状态默认falseisChildOfHeader默认true表示 SideNav 挂在 Header 之下对应cds--side-nav--ux样式独立页面导航可设为falseisFixedNav默认false为true时不渲染遮罩层展开/收起由cds--side-nav--expanded/--collapsed控制isPersistent默认true为false时侧边导航在收起状态下会被隐藏cds--side-nav--hidden并在 lg断点下通过inert属性从可聚焦元素中移除SideNav.tsxisRail开启 rail窄轨模式鼠标悬停/移出与点击会临时展开侧边导航相关事件处理见 SideNav.tsxenterDelayMs展开动画的延迟毫秒数默认100addFocusListeners/addMouseListeners是否添加焦点/鼠标监听默认均为trueonToggle、onOverlayClick、onSideNavBlur展开切换、遮罩点击、失焦时的回调href按 Escape 收起时跳转的目标地址。SideNav 的展开状态会通过 SideNavContext.tsx 以 React Context 向SideNavItems、SideNavMenu等后代传递isRail与isSideNavExpanded子组件据此决定图标/文本的显隐与tabIndex。SideNavHeader / SideNavDetails / SideNavSwitcher侧边导航头部SideNavHeader.tsx渲染侧边导航顶部区域renderIcon必填用于显示品牌或产品图标SideNavDetails.tsx渲染标题title必填输出h2 classcds--side-nav__title可把SideNavSwitcher作为子组件放入SideNavSwitcher.tsx渲染一个select下拉框用于在顶层产品/环境间切换。labelText与options: string[]均为必填onChange在失焦或变更时触发默认第一个 disabled 选项即labelText本身。SideNavHeader renderIcon{ProductIcon} SideNavDetails titlePlatform SideNavSwitcher labelTextEnvironment onChange{(event) setEnv(event.target.value)} options{[Production, Staging, Development]} / /SideNavDetails /SideNavHeaderSideNavItems / SideNavLink / SideNavMenu / SideNavMenuItemSideNavItems.tsx渲染ul classcds--side-nav__items向下传递 SideNavContextSideNavLink.tsx渲染单个链接支持isActive、large大号变体、renderIcon图标以及tabIndex覆盖SideNavMenu.tsx渲染可折叠分组title必填支持defaultExpanded默认false、isActive、large、renderIcon按钮带aria-expanded按 Escape 收起。它还会自动检测后代是否有isActive/aria-current的子项hasActiveDescendant从而在展开前就给分组加上激活态样式SideNavMenu.tsxSideNavMenuItem.tsx分组内的链接项支持isActive、aria-currentpage与多态as。SideNav aria-labelSide navigation SideNavItems SideNavLink renderIcon{DashboardIcon} href/overview Overview /SideNavLink SideNavMenu renderIcon{FolderIcon} titleCategory defaultExpanded SideNavMenuItem href/reportsReport 1/SideNavMenuItem SideNavMenuItem isActive aria-currentpage href/reports/2 Report 2 /SideNavMenuItem /SideNavMenu /SideNavItems /SideNavRightPanel 右侧面板与 Switcher 应用切换器README 中列出的RightPanel在源码中对应 HeaderPanel.tsx。它是一个可展开的面板容器通常配合HeaderGlobalAction使用expanded面板是否展开支持受控addFocusListeners默认true控制失焦/键盘监听onHeaderPanelFocus面板收起时的回调href按 Escape 时跳转的地址。面板内部可放置 Switcher.tsx它渲染一个链接列表cds--switcher要求传入aria-label或aria-labelledby二者取其一并实现方向键焦点循环管理handleSwitcherItemFocus见 Switcher.tsx。其子组件SwitcherItem.tsx单个产品链接支持href、target、rel、isSelectedSwitcherDivider.tsx列表项之间的分隔线。HeaderGlobalAction aria-label{isPanelExpanded ? Close switcher : Open switcher} isActive{isPanelExpanded} onClick{() setIsPanelExpanded(!isPanelExpanded)} tooltipAlignmentend SwitcherIcon size{20} / /HeaderGlobalAction HeaderPanel expanded{isPanelExpanded} href#switcher-button Switcher aria-labelSwitcher Container expanded{isPanelExpanded} SwitcherItem href/app-1App 1/SwitcherItem SwitcherDivider / SwitcherItem href/app-2App 2/SwitcherItem /Switcher /HeaderPanel配套组件Content、SkipToContent 与 HeaderSideNavItemsContent.ts页面主内容容器默认渲染main classcds--content可通过tagName自定义标签如section适合与SkipToContent的锚点配合SkipToContent.tsx无障碍跳过导航链接默认文案为Skip to main content、href为#main-content、tabIndex为 0HeaderSideNavItems.tsx允许把HeaderMenuItem原样复用到 SideNav 内hasDivider默认false可为复用的导航区与下方 SideNav 项之间增加分隔线。SideNav aria-labelSide navigation SideNavItems HeaderSideNavItems hasDivider HeaderMenuItem href/Link 1/HeaderMenuItem HeaderMenuItem href/2Link 2/HeaderMenuItem /HeaderSideNavItems SideNavLink href/otherOther/SideNavLink /SideNavItems /SideNav响应式与无障碍行为来自源码的实现细节Carbon 官方对 Header 的响应式要求是在较小屏幕下带持久化 SideNav 的 Header 应将侧边导航折叠为汉堡菜单。这一行为在源码中有两处直接体现断点感知SideNav 通过carbon/layout的breakpoints.lg构造媒体查询(min-width: lg)并用useMatchMedia判断当前视口SideNav.tsx在非 rail 且未展开且视口小于 lg 时为导航节点设置inert属性将其从 Tab 焦点序列中移除SideNav.tsx。焦点联动当用户 Tab 离开展开的菜单按钮时焦点会被引导到 SideNav 上useWindowEvent(keydown)处理 Tab 键见 SideNav.tsx而Escape键在HeaderContainer、SideNav、HeaderMenu、SideNavMenu、HeaderPanel中均有统一的收起处理保证键盘用户可以随时退出导航层级。交互行为均有对应的单元测试覆盖例如 HeaderMenu-test.js、SideNav-test.js、Switcher-test.js 等可据此验证各组件的展开/收起、键盘导航与激活态逻辑。从示例到落地可运行的整体骨架仓库中的 Storybook 故事文件 UIShell.HeaderBase.stories.js 提供了多个开箱即用的组合示例覆盖以下场景Header with Navigation菜单按钮 产品名 顶栏导航 非持久化 SideNavHeader with Navigation and Actions在上述基础上加入HeaderGlobalBar搜索/通知/应用切换Header with Navigation, Actions and Side Nav完整形态SideNav 内混用HeaderSideNavItems、SideNavMenu与SideNavLinkHeader with Side Nav仅含产品名 SideNav 的轻量布局Header with Actions and Right Panel通知图标 HeaderPanel右侧面板Header with Actions and Switcher应用切换器面板的完整交互。下面是一个精简版的可运行骨架把上述知识点串起来import { Content, Header, HeaderContainer, HeaderMenuButton, HeaderName, HeaderNavigation, HeaderMenuItem, HeaderMenu, HeaderGlobalBar, HeaderGlobalAction, SideNav, SideNavItems, SideNavLink, SideNavMenu, SideNavMenuItem, SkipToContent, } from carbon/react; import { Search, Notification, Fade } from carbon/icons-react; export default function AppShell() { return ( HeaderContainer render{({ isSideNavExpanded, onClickSideNavExpand }) ( Header aria-labelIBM Platform Name SkipToContent / HeaderMenuButton aria-label{isSideNavExpanded ? Close menu : Open menu} onClick{onClickSideNavExpand} isActive{isSideNavExpanded} aria-expanded{isSideNavExpanded} / HeaderName href/ prefixIBM [Platform] /HeaderName HeaderNavigation aria-labelIBM [Platform] HeaderMenuItem href/Link 1/HeaderMenuItem HeaderMenu menuLinkNameLink 2 HeaderMenuItem href/2aSub-link 1/HeaderMenuItem HeaderMenuItem href/2bSub-link 2/HeaderMenuItem /HeaderMenu /HeaderNavigation HeaderGlobalBar HeaderGlobalAction aria-labelSearch onClick{() {}} Search size{20} / /HeaderGlobalAction HeaderGlobalAction aria-labelNotifications onClick{() {}} Notification size{20} / /HeaderGlobalAction /HeaderGlobalBar SideNav aria-labelSide navigation expanded{isSideNavExpanded} isPersistent{false} onSideNavBlur{onClickSideNavExpand} SideNavItems SideNavLink renderIcon{Fade} href/overview Overview /SideNavLink SideNavMenu renderIcon{Fade} titleCategory SideNavMenuItem href/reportsReport/SideNavMenuItem /SideNavMenu /SideNavItems /SideNav /Header Content idmain-content {/* 页面主体内容 */} /Content / )} / ); }小结Carbon 的 UI Shell 通过Header、SideNav、HeaderPanel三大容器及其子组件为产品级应用提供了统一、可访问、响应式的外壳方案顶栏负责品牌与全局操作侧边导航承载次级信息架构右侧面板与 Switcher 完成应用间的切换。理解这些组件各自的 Props、受控/非受控语义以及 Context 传递关系是快速落地一套符合 Carbon 规范导航框架的关键。建议在实际开发中先阅读 UIShell README 掌握组件树再对照 Storybook 示例 选择与业务最匹配的组合形态最后用各组件对应的单元测试如 SideNav-test.js验证交互边界。【免费下载链接】carbonA design system built by IBM项目地址: https://gitcode.com/GitHub_Trending/carbo/carbon创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表