Ant Design响应式导航栏中子菜单分组方法(解决div分组导致布局垂直错位问题)
如何在Ant Design水平导航栏中正确分组子菜单?
嘿,我来帮你搞定这个Ant Design导航栏的问题~你遇到的布局变垂直的问题,核心原因是Ant Design的Menu组件(尤其是mode="horizontal"模式下)只允许它的直接子节点是官方提供的Menu.Item、Menu.SubMenu、Menu.ItemGroup这类组件。如果你用<div>或者空片段<>来包裹一组子菜单,Menu无法识别这些自定义容器,就会破坏原本的水平布局逻辑,导致菜单项变成垂直排列。
下面给你几个针对性的解决方案,根据你的需求选择:
1. 逻辑分组(用于断点控制显示/隐藏)
如果你只是想把这些子菜单逻辑上归为一组,方便后续基于屏幕断点控制显示或隐藏,不需要额外的容器,直接用React的条件渲染结合Ant Design的useBreakpoint钩子就能实现:
import { Menu, useBreakpoint } from 'antd'; import { ShoppingCartOutlined, UserOutlined, DownOutlined } from '@ant-design/icons'; import { useState } from 'react'; const Navbar = () => { const { md } = useBreakpoint(); // md是断点阈值,小于md尺寸时会隐藏分组项 const [menu, setMenu] = useState(null); // 你的Dropdown菜单逻辑 const navbarClasses = []; // 你的自定义类名 const logo = ''; // 你的logo地址 const ukLogo = ''; // 你的语言图标地址 return ( <Menu className={navbarClasses.join(" ")} mode="horizontal" style={{ padding: "5px", fontSize: "15px" }} > <Menu.Item className="logo_bottom"> <img alt="logo" src={logo} className="logo" /> </Menu.Item> {/* 基于断点控制这一组菜单项的显示 */} {md && ( <> <Menu.SubMenu title="Demos" style={{ marginTop: "14px" }}> <Menu.Item> <a target="_blank" rel="noopener noreferrer" href="https://www.antgroup.com">Modern</a> </Menu.Item> <Menu.Item>Classic</Menu.Item> <Menu.Item>Vintage</Menu.Item> <Menu.Item>Standard</Menu.Item> <Menu.Item>Minimal</Menu.Item> <Menu.Item>Trendy</Menu.Item> <Menu.Item>Elegant</Menu.Item> </Menu.SubMenu> <Menu.SubMenu key="smenu" title="Categories" style={{ marginTop: "14px" }}> <Menu.Item className="ant-dropdown-link">Fresh Vegetables</Menu.Item> <Menu.Item>Diet Nutrition</Menu.Item> <Menu.Item>Healthy Foods</Menu.Item> <Menu.Item>Grocery Items</Menu.Item> <Menu.Item>Beaf Steak</Menu.Item> </Menu.SubMenu> <Menu.SubMenu key="ssmenu" title="Dietary" style={{ marginTop: "14px" }}> <Menu.Item className="ant-dropdown-link">Vegetarian</Menu.Item> <Menu.Item>Kakogenic</Menu.Item> <Menu.Item>Mediterranean</Menu.Item> <Menu.Item>Organic</Menu.Item> </Menu.SubMenu> <Menu.Item style={{ marginTop: "14px" }}>Search</Menu.Item> <Menu.SubMenu title="Pages" style={{ marginRight: "auto", marginTop: "14px" }}> <Menu.SubMenu title="Users"> <Menu.Item>My Account</Menu.Item> <Menu.Item>Sign In</Menu.Item> <Menu.Item>Sign Up</Menu.Item> </Menu.SubMenu> <Menu.Item>FAQ About Us</Menu.Item> <Menu.Item>Privacy Policy</Menu.Item> <Menu.Item>Terms & Condition</Menu.Item> <Menu.Item>Contact Us</Menu.Item> <Menu.Item>Checkout</Menu.Item> <Menu.Item>404</Menu.Item> </Menu.SubMenu> </> )} {/* 右侧始终显示的菜单项 */} <Menu.Item style={{ marginTop: "14px" }}> <Menu.Dropdown overlay={menu} trigger={["click"]}> <a className="ant-dropdown-link" onClick={(e) => e.preventDefault()}> <img alt="uk" src={ukLogo} className="lan-images" /> English - EN <DownOutlined /> </a> </Menu.Dropdown> </Menu.Item> <Menu.Item style={{ marginTop: "14px" }}> <button icon={<ShoppingCartOutlined style={{ fontSize: "20px" }} />} type="text" size="large"> Cart </button> </Menu.Item> <Menu.Item style={{ marginTop: "14px" }}> <button icon={<UserOutlined style={{ fontSize: "20px" }} />} type="text" shape="round"> Sign In </button> </Menu.Item> </Menu> ); };
2. 视觉分组(添加分隔线)
如果需要在视觉上区分不同组的菜单项,可以使用Ant Design内置的Menu.Divider组件(垂直分隔线),不需要自定义容器:
<Menu mode="horizontal"> {/* 第一组菜单项 */} <Menu.SubMenu title="Demos">...</Menu.SubMenu> <Menu.SubMenu title="Categories">...</Menu.SubMenu> <Menu.SubMenu title="Dietary">...</Menu.SubMenu> {/* 垂直分隔线,视觉上分组 */} <Menu.Divider type="vertical" /> {/* 第二组菜单项 */} <Menu.Item>Search</Menu.Item> <Menu.SubMenu title="Pages">...</Menu.SubMenu> </Menu>
3. 小屏幕适配(转为汉堡菜单)
如果你的需求是在小屏幕上隐藏这组子菜单,改用汉堡菜单触发显示,那可以结合Drawer组件实现响应式适配:
import { Menu, useBreakpoint, Drawer, Button, Dropdown } from 'antd'; import { MenuOutlined, ShoppingCartOutlined, UserOutlined, DownOutlined } from '@ant-design/icons'; import { useState } from 'react'; const Navbar = () => { const { md } = useBreakpoint(); const [drawerVisible, setDrawerVisible] = useState(false); const [menu, setMenu] = useState(null); const navbarClasses = []; const logo = ''; const ukLogo = ''; // 抽屉内的菜单内容 const drawerMenu = ( <Menu mode="vertical"> <Menu.SubMenu title="Demos"> <Menu.Item>Modern</Menu.Item> <Menu.Item>Classic</Menu.Item> <Menu.Item>Vintage</Menu.Item> </Menu.SubMenu> <Menu.SubMenu title="Categories"> <Menu.Item>Fresh Vegetables</Menu.Item> <Menu.Item>Diet Nutrition</Menu.Item> </Menu.SubMenu> <Menu.SubMenu title="Dietary"> <Menu.Item>Vegetarian</Menu.Item> <Menu.Item>Mediterranean</Menu.Item> </Menu.SubMenu> <Menu.Item>Search</Menu.Item> <Menu.SubMenu title="Pages"> <Menu.SubMenu title="Users"> <Menu.Item>My Account</Menu.Item> <Menu.Item>Sign In</Menu.Item> </Menu.SubMenu> </Menu.SubMenu> </Menu> ); return ( <> <Menu className={navbarClasses.join(" ")} mode="horizontal" style={{ padding: "5px", fontSize: "15px" }} > <Menu.Item className="logo_bottom"> <img alt="logo" src={logo} className="logo" /> </Menu.Item> {/* 大屏幕显示完整菜单项 */} {md && ( <> <Menu.SubMenu title="Demos" style={{ marginTop: "14px" }}> {/* 子项内容 */} </Menu.SubMenu> <Menu.SubMenu key="smenu" title="Categories" style={{ marginTop: "14px" }}> {/* 子项内容 */} </Menu.SubMenu> {/* 其他子菜单... */} </> )} {/* 小屏幕显示汉堡按钮 */} {!md && ( <Menu.Item> <Button icon={<MenuOutlined />} onClick={() => setDrawerVisible(true)} /> </Menu.Item> )} {/* 右侧固定菜单项 */} <Menu.Item style={{ marginTop: "14px" }}> <Dropdown overlay={menu} trigger={["click"]}> <a className="ant-dropdown-link" onClick={(e) => e.preventDefault()}> <img alt="uk" src={ukLogo} className="lan-images" /> English - EN <DownOutlined /> </a> </Dropdown> </Menu.Item> <Menu.Item style={{ marginTop: "14px" }}> <Button icon={<ShoppingCartOutlined style={{ fontSize: "20px" }} />} type="text" size="large"> Cart </Button> </Menu.Item> <Menu.Item style={{ marginTop: "14px" }}> <Button icon={<UserOutlined style={{ fontSize: "20px" }} />} type="text" shape="round"> Sign In </Button> </Menu.Item> </Menu> {/* 小屏幕抽屉菜单 */} <Drawer title="Navigation Menu" placement="left" onClose={() => setDrawerVisible(false)} open={drawerVisible} width={280} > {drawerMenu} </Drawer> </> ); };
核心要点就是:Ant Design的水平Menu不支持自定义容器作为直接子节点,必须使用官方提供的Menu系列组件,分组逻辑可以通过响应式钩子、内置分隔线或者小屏幕适配组件来实现。
内容的提问来源于stack exchange,提问作者Anwar Hossain
相关产品推荐
相关产品推荐

