React MUI布局中汉堡按钮在大屏设备下无法切换侧边栏的问题解决
React MUI布局中汉堡按钮在大屏设备下无法切换侧边栏的问题解决
我完全懂你现在的困扰——你这套React + Material UI的布局里,汉堡按钮只能在小屏幕上切换侧边栏,到大屏设备时侧边栏就固定显示着,按钮完全没作用,想让它在所有屏幕尺寸下都有一致的切换行为对吧?别担心,咱们来搞定这个问题。
问题根源
原来的代码里,大屏设备用的是variant="permanent"的Drawer组件,而且直接把open属性设为true,这就导致它一直固定显示,完全不受侧边栏状态的控制;而汉堡按钮的点击事件只关联了小屏用的临时Drawer,自然在大屏上没效果。
解决方案思路
我们要让所有屏幕尺寸下的侧边栏都受同一个状态控制,把大屏的Drawer改成可受控的模式,同时调整样式适配侧边栏收起/展开的状态,最后让汉堡按钮的行为在全尺寸下统一。
修改后的完整代码
import * as React from "react"; import AppBar from "@mui/material/AppBar"; import Box from "@mui/material/Box"; import CssBaseline from "@mui/material/CssBaseline"; import Divider from "@mui/material/Divider"; import Drawer from "@mui/material/Drawer"; import IconButton from "@mui/material/IconButton"; import InboxIcon from "@mui/icons-material/MoveToInbox"; import List from "@mui/material/List"; import ListItem from "@mui/material/ListItem"; import ListItemButton from "@mui/material/ListItemButton"; import ListItemIcon from "@mui/material/ListItemIcon"; import ListItemText from "@mui/material/ListItemText"; import MailIcon from "@mui/icons-material/Mail"; import MenuIcon from "@mui/icons-material/Menu"; import Toolbar from "@mui/material/Toolbar"; import Typography from "@mui/material/Typography"; const drawerWidth = 240; interface Props { window?: () => Window; } export default function ResponsiveDrawer(props: Props) { const { window } = props; // 用一个统一的状态控制所有屏幕下的侧边栏显示 const [isDrawerOpen, setIsDrawerOpen] = React.useState(true); const [isClosing, setIsClosing] = React.useState(false); const handleDrawerClose = () => { setIsClosing(true); setIsDrawerOpen(false); }; const handleDrawerTransitionEnd = () => { setIsClosing(false); }; const handleDrawerToggle = () => { if (!isClosing) { setIsDrawerOpen(!isDrawerOpen); } }; const drawer = ( <div> <Toolbar /> <Divider /> <List> {["Inbox", "Starred", "Send email", "Drafts"].map((text, index) => ( <ListItem key={text} disablePadding> <ListItemButton> <ListItemIcon> {index % 2 === 0 ? <InboxIcon /> : <MailIcon />} </ListItemIcon> <ListItemText primary={text} /> </ListItemButton> </ListItem> ))} </List> <Divider /> <List> {["All mail", "Trash", "Spam"].map((text, index) => ( <ListItem key={text} disablePadding> <ListItemButton> <ListItemIcon> {index % 2 === 0 ? <InboxIcon /> : <MailIcon />} </ListItemIcon> <ListItemText primary={text} /> </ListItemButton> </ListItem> ))} </List> </div> ); const container = window !== undefined ? () => window().document.body : undefined; return ( <Box sx={{ display: "flex" }}> <CssBaseline /> <AppBar position="fixed" sx={{ zIndex: (theme) => theme.zIndex.drawer + 1, // 侧边栏收起时,AppBar占满宽度 width: isDrawerOpen ? { sm: `calc(100% - ${drawerWidth}px)` } : "100%" }} > <Toolbar> <IconButton color="inherit" aria-label="open drawer" edge="start" onClick={handleDrawerToggle} sx={{ mr: 2 }} > <MenuIcon /> </IconButton> <Typography variant="h6" noWrap component="div"> Responsive drawer </Typography> </Toolbar> </AppBar> <Box component="nav" sx={{ flexShrink: { sm: 0 }, width: isDrawerOpen ? { sm: drawerWidth } : { sm: 0 } }} aria-label="mailbox folders" > {/* 小屏用临时Drawer */} <Drawer container={container} variant="temporary" open={isDrawerOpen} onTransitionEnd={handleDrawerTransitionEnd} onClose={handleDrawerClose} ModalProps={{ keepMounted: true }} sx={{ display: { xs: "block", sm: "none" }, "& .MuiDrawer-paper": { boxSizing: "border-box", width: drawerWidth } }} > {drawer} </Drawer> {/* 大屏用持久化Drawer,受isDrawerOpen状态控制 */} <Drawer variant="persistent" open={isDrawerOpen} sx={{ display: { xs: "none", sm: "block" }, "& .MuiDrawer-paper": { boxSizing: "border-box", width: drawerWidth } }} > {drawer} </Drawer> </Box> <Box component="main" sx={{ flexGrow: 1, p: 3, // 内容区域宽度随侧边栏状态变化 width: isDrawerOpen ? { sm: `calc(100% - ${drawerWidth}px)` } : "100%" }} > <Toolbar /> <Typography>aaa</Typography> <Typography>bbb</Typography> </Box> </Box> ); }
关键修改点说明
- 统一状态控制:把原来仅控制小屏的状态换成了
isDrawerOpen,用来统一控制所有屏幕尺寸下侧边栏的显示/隐藏状态,汉堡按钮的点击事件直接切换这个状态。 - 大屏Drawer改为持久化模式:把大屏的
variant="permanent"换成variant="persistent",这样它可以被收起/展开,并且通过open={isDrawerOpen}绑定状态,不再固定显示。 - 自适应样式调整:给AppBar和主内容区域都添加了根据
isDrawerOpen状态变化的宽度样式,确保侧边栏收起时,顶部导航和内容能占满整个屏幕宽度,展开时自动留出侧边栏的空间。 - 保持小屏原有体验:小屏的临时Drawer逻辑不变,依然保留了过渡动画和移动端优化的
keepMounted属性。
这样修改之后,不管是手机端还是大屏设备,汉堡按钮都能完美控制侧边栏的显示和隐藏,行为完全一致啦!
内容来源于stack exchange
相关产品推荐
相关产品推荐

