You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Material-UI Drawer组件temporary变体桌面端不显示问题

解决Material-UI Drawer响应式显示问题(移动端可切换,桌面端永久显示)

你当前的问题出在两个核心点:

  • sx样式里设置了display: { xs: 'block', sm: 'none' },导致屏幕尺寸大于sm时Drawer直接被隐藏
  • 没有区分移动端和桌面端的Drawer变体,且open状态未根据屏幕尺寸适配,桌面端需要永久显示,不能依赖mobileOpen状态

解决方案

借助MUI的useMediaQuery钩子判断屏幕尺寸,针对移动端和桌面端分别配置Drawer的变体、open状态和显示逻辑,同时添加移动端的菜单触发按钮。

修改后的完整代码

import React from "react";
import { useHistory } from "react-router-dom";
import { useMediaQuery, useTheme, makeStyles, Typography, Drawer, Toolbar, Divider, List, ListItem, ListItemText, ListItemIcon, Container, Box, IconButton } from "@material-ui/core";
import MenuIcon from '@material-ui/icons/Menu';

import HomeOutlinedIcon from '@material-ui/icons/HomeOutlined';
import AlternateEmailOutlinedIcon from '@material-ui/icons/AlternateEmailOutlined';
import NotificationsNoneOutlinedIcon from '@material-ui/icons/NotificationsNoneOutlined';
import DashboardOutlinedIcon from '@material-ui/icons/DashboardOutlined';
import ArchiveOutlinedIcon from '@material-ui/icons/ArchiveOutlined';

const drawerWidth = 280;

const useStyles = makeStyles((theme) => ({
    drawer: {
        width: drawerWidth,
    },
    drawerPaper: {
        width: drawerWidth,
    },
    list: {
        marginLeft: '24px',
        marginRight: '24px'
    },
    listItem: {
        padding: '8px',
        borderRadius: '5px',
    },
    text: {
        color: theme.palette.primary.light,
        fontWeight: '500',
        lineHeight: '2000'
    },
    title: {
        color: theme.palette.primary.light,
        textAlign: 'center',
        display: 'block',
        fontWeight: '500',
        fontSize: '20px',
        marginTop: '10px',
        marginBottom: '10px'
    },
    menuButton: {
        marginRight: theme.spacing(2),
        [theme.breakpoints.up('sm')]: {
            display: 'none',
        },
    },
}));

export default function LeftBar() {
    const classes = useStyles();
    const theme = useTheme();
    const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
    const [mobileOpen, setMobileOpen] = React.useState(false);

    const handleDrawerToggle = () => {
        setMobileOpen(!mobileOpen);
    };

    const list = [
        { text: 'Home', icon: <HomeOutlinedIcon />, path: '/' },
        { text: 'Personal', icon: <AlternateEmailOutlinedIcon />, path: '/' },
        { text: 'Notificatons', icon: <NotificationsNoneOutlinedIcon />, path: '/' },
        { text: 'Dashboard', icon: <DashboardOutlinedIcon />, path: '/' },
        { text: 'Archives', icon: <ArchiveOutlinedIcon />, path: '/' }
    ];

    return (
        <Box>
            {/* 移动端菜单触发按钮 */}
            <Toolbar>
                <IconButton
                    color="inherit"
                    aria-label="open drawer"
                    edge="start"
                    onClick={handleDrawerToggle}
                    className={classes.menuButton}
                >
                    <MenuIcon />
                </IconButton>
            </Toolbar>

            <Drawer
                className={classes.drawer}
                anchor="left"
                classes={{ paper: classes.drawerPaper }}
                // 桌面端永久打开,移动端由mobileOpen控制
                open={isMobile ? mobileOpen : true}
                // 只有移动端需要关闭事件
                onClose={isMobile ? handleDrawerToggle : undefined}
                // 根据屏幕尺寸选择变体:移动端用temporary,桌面端用permanent
                variant={isMobile ? 'temporary' : 'permanent'}
                ModalProps={{ keepMounted: true }}
                sx={{
                    // 桌面端始终显示,移动端不隐藏
                    display: { xs: 'block', sm: 'block' },
                    flexShrink: 0,
                    '& .MuiDrawer-paper': { boxSizing: 'border-box', width: drawerWidth },
                }}
            >
                <Toolbar />
                <Container>
                    <Typography variant="h5" component="h2" className={classes.title} gutterBottom>
                        My Account
                    </Typography>
                </Container>
                <Divider />

                <List className={classes.list}>
                    {list.map((item) => (
                        <ListItem key={item.text} className={classes.listItem} button>
                            <ListItemIcon className={classes.icon}>
                                {item.icon}
                            </ListItemIcon>
                            <ListItemText sx={{ color: 'primary' }} primary={item.text} className={classes.text} />
                        </ListItem>
                    ))}
                </List>
            </Drawer>
        </Box>
    );
};

关键修改点说明

  • 引入useMediaQuery和useTheme钩子,判断当前是否为移动端(屏幕尺寸≤sm)
  • 添加移动端专属的菜单触发按钮,桌面端自动隐藏
  • 动态设置Drawer的variant:移动端用temporary(可临时弹出),桌面端用permanent(永久显示)
  • 动态设置open状态:桌面端始终为true,移动端由mobileOpen状态控制
  • 修改sx的display属性,确保桌面端Drawer不被隐藏
  • 只有移动端需要设置onClose事件,桌面端无需关闭逻辑

内容的提问来源于stack exchange,提问作者Morri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 11:48:59