news 2026/10/8 2:04:25

rsuite Sidenav 完整布局实战:Header、Body 与 Footer Toggle 折叠导航栏

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
rsuite Sidenav 完整布局实战:Header、Body 与 Footer Toggle 折叠导航栏
  • 前端
  • UI组件

【免费下载链接】rsuite

🧱 A suite of React components .

项目地址:https://gitcode.com/gh_mirrors/rs/rsuite
点击查看免费下载

本文以 rsuite 文档中 Sidenav footer 示例 为骨架,讲解如何用Sidenav、Nav、Sidenav.Toggle以及HStack/VStack/InputGroup等布局组件,构建一个带品牌区、搜索框与折叠开关的完整侧边导航栏。读完本文,你将掌握 Sidenav 三段式结构(Header / Body / Footer)的组装方式、expanded受控状态的切换原理,以及折叠态下组件如何联动响应,并能在自己的 React 项目中直接复刻这套代码。

一、示例目标:一个可折叠的完整侧边栏

docs/pages/components/sidenav/fragments/footer.md给出的示例,是一个典型的后台管理系统侧边栏:顶部是品牌 Logo 与搜索框,中间是五个带图标的导航菜单项,底部是展开/折叠切换按钮。整体结构如下:

<Box w={240}> <Sidenav expanded={expanded}> <Sidenav.Header> <Header expanded={expanded} /> </Sidenav.Header> <Sidenav.Body> <Nav> <Nav.Item icon={<DashboardIcon />}>Overview</Nav.Item> {/* ... 其余菜单项 */} </Nav> </Sidenav.Body> <Sidenav.Footer> <Sidenav.Toggle onToggle={setExpanded} /> </Sidenav.Footer> </Sidenav> </Box>

在这个示例中,Box w={240}为侧边栏设置了固定宽度容器;expanded是一个React.useState(true)管理的受控状态,由Sidenav.Toggle的onToggle回调驱动更新。从 src/Sidenav/Sidenav.tsx 源码可以看到,Sidenav的expanded属性默认值为true,并通过Transition(timeout={300})为宽度变化提供 300ms 的折叠/展开过渡动画。

二、三段式结构:Header / Body / Footer 的职责划分

Sidenav组件通过静态子组件(Subcomponents)挂载了Header、Body、Footer、GroupLabel、Toggle五个子组件(见 src/Sidenav/Sidenav.tsx)。其中Header、Body、Footer本身是纯粹的结构化容器,由createComponent生成为普通div元素(见 SidenavHeader.tsx、SidenavBody.tsx、SidenavFooter.tsx),真正的行为逻辑由Nav与Sidenav.Toggle承载。

1. Header:品牌区与搜索框的折叠联动

示例中的Header是一个自定义组件,根据expanded状态切换渲染内容:

const Header = ({ expanded }) => { if (!expanded) { return ( <HStack justifyContent="center"> <SiProtondb size={32} /> </HStack> ); } return ( <VStack p="10px 10px 0 10px" spacing={12}> <HStack> <SiProtondb size={32} /> Brand </HStack> <InputGroup inside size="sm"> <InputGroup.Addon> <SearchIcon /> </InputGroup.Addon> <Input type="search" placeholder="Search here..." /> </InputGroup> </VStack> ); };
  • 折叠态(expanded === false):只居中显示品牌图标,避免在窄条侧边栏中撑开宽度。
  • 展开态:使用VStack(垂直排列)组合「品牌名 + 搜索框」,spacing={12}控制垂直间距;InputGroup inside实现图标内嵌的搜索输入框,配合@rsuite/icons/Search图标。
  • 搜索框在折叠时被移除,这是侧边栏折叠设计的常见做法,因为 52px 宽的窄条无法容纳输入控件。

对应样式上,src/Sidenav/styles/index.scss中.rs-sidenav-header通过padding: var(--rs-sidenav-header-p)控制内边距,而折叠态(.rs-sidenav-collapse-out)会隐藏所有.rs-sidenav-item-title文本,仅保留居中的图标。

2. Body:菜单导航的核心区域

Sidenav.Body内部渲染Nav组件及五个Nav.Item,每个菜单项都通过icon属性挂载@rsuite/icons图标:

<Nav> <Nav.Item icon={<DashboardIcon />}>Overview</Nav.Item> <Nav.Item icon={<PeoplesIcon />}>Customers</Nav.Item> <Nav.Item icon={<PieChartIcon />}>Analytics</Nav.Item> <Nav.Item icon={<DataAuthorizeIcon />}>Security</Nav.Item> <Nav.Item icon={<SettingIcon />}>Settings</Nav.Item> </Nav>

从样式源码看,.rs-sidenav-body采用flex: 1 1 auto; overflow: auto,保证菜单区域在侧边栏中自动撑满剩余高度,并在内容超长时可滚动;折叠时(.rs-sidenav-collapse-out .rs-sidenav-body)则改为overflow: inherit,让下拉子菜单可以溢出显示。折叠态下,.rs-sidenav-item会通过justify-content: center与height: var(--rs-sidenav-item-height)(36px)实现图标垂直居中的窄条样式,并隐藏文字标题。

3. Footer:折叠开关的挂载位置

Sidenav.Footer在样式上拥有自己的职责:src/Sidenav/styles/index.scss中.rs-sidenav-footer设置了border-top: 1px solid(上边框)、margin-top: auto(推到容器底部)以及padding: var(--rs-sidenav-footer-p)。示例将Sidenav.Toggle放在此处,视觉上形成「菜单列表 → 分隔线 → 折叠按钮」的经典底栏布局。

三、Sidenav.Toggle:折叠开关的工作原理

Sidenav.Toggle是本示例的核心交互元素,其实现位于 src/Sidenav/SidenavToggle.tsx:

const sidenav = useContext(SidenavContext); if (!sidenav) { console.error('<Sidenav.Toggle> must be rendered within a <Sidenav>'); return null; } const expanded = sidenav.expanded; const handleToggle = useEventCallback((event) => { onToggle?.(!expanded, event); onClick?.(event); }); return ( <IconButton icon={<ArrowLeftLineIcon aria-label="" />} onClick={handleToggle} aria-label={expanded ? 'Collapse' : 'Expand'} {...rest} /> );

几个关键实现细节:

  1. 依赖 Sidenav Context:Sidenav.Toggle通过useContext(SidenavContext)读取expanded状态。若被渲染在Sidenav之外,会输出错误信息并返回null。SidenavContext在 src/Sidenav/SidenavContext.tsx 中定义,由Sidenav在渲染时通过SidenavContext.Provider注入expanded、openKeys、onOpenChange等值。
  2. 受控回调:点击按钮时调用onToggle(!expanded, event)。示例中的onToggle={setExpanded}直接把新的展开状态写回 React state,实现真正的受控折叠。
  3. 无障碍支持:按钮的aria-label随状态切换为'Collapse'或'Expand',折叠时图标(ArrowLeftLineIcon)旋转 180°(样式见.rs-sidenav-toggle-collapsed .rs-icon)。
  4. 图标动画:.rs-sidenav-toggle的图标transition: transform 0.3s ease,折叠/展开时箭头平滑旋转。

在 SidenavToggle 测试 中验证了这些行为:展开态渲染Collapse按钮、折叠态渲染Expand按钮、点击触发onToggle(false, event),以及脱离Sidenav渲染时抛出错误。

四、样式与动画:折叠如何“动”起来

侧边栏的宽度切换并非瞬间完成,而是由 src/Sidenav/Sidenav.tsx 中的Transition组件驱动:根据expanded状态,在展开(collapse-in)、折叠(collapse-out)与过渡(collapsing)三种 className 间切换。

对应的样式定义在 src/Sidenav/styles/index.scss:

CSS 变量默认值作用
--rs-sidenav-width52px折叠态侧边栏宽度
--rs-sidenav-collapse-in-width100%展开态宽度(撑满容器)
--rs-sidenav-collapse-transition0.15s ease-in宽度过渡时长与缓动
--rs-sidenav-item-height36px折叠态菜单项高度
--rs-sidenav-header-p/--rs-sidenav-footer-p派生自--rs-sidenav-pHeader / Footer 内边距
  • 展开态.rs-sidenav-collapse-in将宽度设为100%,菜单文字、搜索框等全部可见;
  • 折叠态.rs-sidenav-collapse-out将宽度收缩到52px,文字通过sideNavFoldedText关键帧动画淡出(max-width200px → 0,透明度 0.8 → 0);
  • 折叠后的下拉菜单(.rs-dropdown-menu)会脱离窄条,以浮层形式从inset-inline-start: 28px位置展开——这正是示例中折叠后仅剩图标、点击可弹出子菜单的基础。

需要说明的是,示例中的Box w={240}是侧边栏展开时的容器宽度;实际项目中也可以让Sidenav直接占据布局宽度,并通过expanded切换实现「宽 240px ⇆ 窄 52px」的布局自适应。

五、完整可运行示例

将示例中的ReactDOM.render替换为现代 React 的createRoot后,完整代码可直接运行(需安装rsuite、@rsuite/icons、react-icons):

import { useState } from 'react'; import DashboardIcon from '@rsuite/icons/Dashboard'; import PeoplesIcon from '@rsuite/icons/Peoples'; import SettingIcon from '@rsuite/icons/Setting'; import PieChartIcon from '@rsuite/icons/PieChart'; import DataAuthorizeIcon from '@rsuite/icons/DataAuthorize'; import SearchIcon from '@rsuite/icons/Search'; import { Sidenav, Nav, HStack, VStack, Input, InputGroup, Box } from 'rsuite'; import { SiProtondb } from 'react-icons/si'; const Header = ({ expanded }) => { if (!expanded) { return ( <HStack justifyContent="center"> <SiProtondb size={32} /> </HStack> ); } return ( <VStack p="10px 10px 0 10px" spacing={12}> <HStack> <SiProtondb size={32} /> Brand </HStack> <InputGroup inside size="sm"> <InputGroup.Addon> <SearchIcon /> </InputGroup.Addon> <Input type="search" placeholder="Search here..." /> </InputGroup> </VStack> ); }; const App = () => { const [expanded, setExpanded] = useState(true); return ( <Box w={240}> <Sidenav expanded={expanded}> <Sidenav.Header> <Header expanded={expanded} /> </Sidenav.Header> <Sidenav.Body> <Nav> <Nav.Item icon={<DashboardIcon />}>Overview</Nav.Item> <Nav.Item icon={<PeoplesIcon />}>Customers</Nav.Item> <Nav.Item icon={<PieChartIcon />}>Analytics</Nav.Item> <Nav.Item icon={<DataAuthorizeIcon />}>Security</Nav.Item> <Nav.Item icon={<SettingIcon />}>Settings</Nav.Item> </Nav> </Sidenav.Body> <Sidenav.Footer> <Sidenav.Toggle onToggle={setExpanded} /> </Sidenav.Footer> </Sidenav> </Box> ); }; export default App;

六、进阶:折叠态下的菜单与状态管理

Sidenav不止于视觉折叠,还通过openKeys机制管理多级菜单的展开状态:

  • defaultOpenKeys:非受控模式下默认展开的菜单eventKey数组;
  • openKeys+onOpenChange:受控模式下由外部接管菜单开合;
  • 折叠态下点击带有子菜单的菜单项时,会以浮层 + Tooltip 形式展示子菜单——这在 Sidenav 测试 中有明确验证(mouseOver弹出tooltip,点击后关闭)。

此外,appearance属性支持'default' | 'inverse' | 'subtle'三种风格,分别对应 styles/index.scss 中的默认浅色、深色反白与透明背景三套样式,均通过data-appearance属性区分。activeKey与onSelect已标记为@deprecated,官方建议改用<Nav activeKey>与<Nav onSelect>(见 src/Sidenav/Sidenav.tsx),示例代码中正是采用「在Sidenav.Body内放Nav」的推荐写法,路由切换时只需给Nav传入activeKey即可高亮当前菜单。

七、总结

footer.md示例演示了 rsuiteSidenav组件的完整三段式组装:Sidenav.Header承载品牌与搜索(随expanded联动显隐),Sidenav.Body承载Nav菜单,Sidenav.Footer挂载Sidenav.Toggle完成折叠开关。其背后是SidenavContext对expanded的共享注入、Transition组件的 300ms 动画驱动,以及 CSS 变量与关键帧动画对窄条折叠态的样式支撑。掌握这套模式后,你可以轻松在管理后台、数据看板等场景中快速落地一个可折叠、可无障碍操作的侧边导航。

相关源码索引:Sidenav 主组件、Sidenav.Toggle、SidenavContext、Sidenav 样式、Sidenav 测试

  • 前端
  • UI组件

【免费下载链接】rsuite

🧱 A suite of React components .

项目地址:https://gitcode.com/gh_mirrors/rs/rsuite
点击查看免费下载

相关推荐

上一篇:Argo Workflows Inputs 机制全解析:模板间参数、工件与卷的传递模型(含 Java SDK 类型说明)
下一篇:PHP-CS-Fixer `numeric_literal_separator` 规则完全指南:为数字字面量自动添加/移除下划线分隔符

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/8 2:02:59

RDMA核心技术解析:WQ、QP、CQ工作原理与RoCEv2实战避坑

简介&#xff1a;本资源是一份系统性的RDMA技术调研报告&#xff0c;面向网络工程师、高性能计算开发者及云计算架构师等技术人员&#xff0c;聚焦低延迟通信场景下的核心加速技术原理与落地实践。内容涵盖RDMA基础概念、零拷贝/内核旁路/CPU卸载三大优势解析&#xff0c;Infin…

作者头像 李华
网站建设 2026/10/8 2:02:30

Chrome MCP Server MCP 服务说明文档

1. 服务概述一句话简介&#xff1a;通过MCP提供Chrome DevTools Protocol集成&#xff0c;允许您通过连接到Chrome的开发者工具来调试Web应用程序。服务名称&#xff1a;Chrome MCP Server版本号&#xff1a;最新版本开发者/提供方&#xff1a;benjaminr协议类型&#xff1a;MC…

作者头像 李华
网站建设 2026/10/8 2:00:17

从最小循环到可靠系统:AI Agent工程化实践指南

去年我花了两个晚上写出了人生第一个真正的Agent&#xff1a;模型拿到用户问题&#xff0c;自己决定调用天气接口&#xff0c;把结果包装成一段回答。跑通的那一刻真的很兴奋——AI Agent原来就是这么回事。但第三天冷静下来&#xff0c;我发现这个最小循环只在演示环境里成立。…

作者头像 李华