【Material-UI】Responsive App Bar with Drawer 详解

Material-UI 是 React 开发中极受欢迎的 UI 框架,它提供了大量的组件来简化 UI 设计和开发。本文将深入介绍如何使用 Material-UI 创建一个响应式的 App Bar 结合 Drawer,实现移动端与桌面端的无缝切换。

一、App Bar 和 Drawer 组件简介

1. App Bar 组件

App Bar 是 Material-UI 中常用的导航栏组件,通常放置在页面顶部,用于显示应用标题、导航按钮和其他操作项。在响应式设计中,App Bar 会根据屏幕宽度做出相应的布局调整,如隐藏多余的按钮或显示一个用于触发侧边栏的汉堡菜单。

2. Drawer 组件

Drawer 是一个侧边导航栏组件,可以从屏幕的一侧滑出,用于显示导航选项。Drawer 在移动设备上尤其常用,因为它能够节省屏幕空间。通过点击汉堡菜单,用户可以打开或关闭 Drawer

3. 响应式设计

在响应式布局中,桌面端的导航通常以 App Bar 的按钮形式展示,而在移动端则使用 Drawer 来展示更多选项。因此,设计一个既适合桌面端又适合移动端的导航栏显得尤为重要。

二、实现 Responsive App Bar with Drawer

我们将结合 App BarDrawer 组件,构建一个可响应不同屏幕尺寸的导航系统。对于桌面端,我们将显示一个水平排列的导航按钮,而在移动端,我们将隐藏按钮,转而展示一个 Drawer

1. 项目结构

在 React 中,常见的文件组织结构如下:

src/
│── components/
│   └── DrawerAppBar.js   # 包含 App Bar 和 Drawer 逻辑的主组件
│── App.js               # 应用的主入口
└── index.js             # React 应用的入口文件

2. 编写 DrawerAppBar 组件

首先,在 DrawerAppBar.js 中引入所需的 Material-UI 组件:

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 List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemText from '@mui/material/ListItemText';
import MenuIcon from '@mui/icons-material/Menu';
import Toolbar from '@mui/material/Toolbar';
import Typography from '@mui/material/Typography';
import Button from '@mui/material/Button';

3. 定义组件逻辑

接下来定义 DrawerAppBar 组件,主要逻辑包括:

  • 状态 mobileOpen 控制 Drawer 的开关状态。
  • handleDrawerToggle 用于在移动端点击汉堡菜单时,打开或关闭 Drawer。
const drawerWidth = 240;
const navItems = ['Home', 'About', 'Contact'];

function DrawerAppBar(props) {
  const { window } = props;
  const [mobileOpen, setMobileOpen] = React.useState(false);

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

4. App Bar 的实现

在 App Bar 中,我们通过 Toolbar 组件包含导航按钮和应用标题。对于移动设备,我们使用 MenuIcon 作为汉堡菜单,点击时调用 handleDrawerToggle 打开 Drawer

<AppBar component="nav">
  <Toolbar>
    <IconButton
      color="inherit"
      aria-label="open drawer"
      edge="start"
      onClick={handleDrawerToggle}
      sx={{ mr: 2, display: { sm: 'none' } }}
    >
      <MenuIcon />
    </IconButton>
    <Typography
      variant="h6"
      component="div"
      sx={{ flexGrow: 1, display: { xs: 'none', sm: 'block' } }}
    >
      MUI
    </Typography>
    <Box sx={{ display: { xs: 'none', sm: 'block' } }}>
      {navItems.map((item) => (
        <Button key={item} sx={{ color: '#fff' }}>
          {item}
        </Button>
      ))}
    </Box>
  </Toolbar>
</AppBar>

5. Drawer 的实现

Drawer 在移动端作为侧边导航栏出现,当用户点击汉堡菜单时,Drawer 将滑出,展示导航选项。

<nav>
  <Drawer
    container={container}
    variant="temporary"
    open={mobileOpen}
    onClose={handleDrawerToggle}
    ModalProps={{
      keepMounted: true, // 保持挂载状态,提升性能
    }}
    sx={{
      display: { xs: 'block', sm: 'none' },
      '& .MuiDrawer-paper': { boxSizing: 'border-box', width: drawerWidth },
    }}
  >
    {drawer}
  </Drawer>
</nav>

drawer 变量包含了 Drawer 的内容,包括导航项和应用标题。点击 Drawer 时也会自动关闭。

const drawer = (
  <Box onClick={handleDrawerToggle} sx={{ textAlign: 'center' }}>
    <Typography variant="h6" sx={{ my: 2 }}>
      MUI
    </Typography>
    <Divider />
    <List>
      {navItems.map((item) => (
        <ListItem key={item} disablePadding>
          <ListItemButton sx={{ textAlign: 'center' }}>
            <ListItemText primary={item} />
          </ListItemButton>
        </ListItem>
      ))}
    </List>
  </Box>
);

6. 响应式布局

通过 sx 属性,我们可以轻松地控制元素在不同屏幕尺寸下的显示情况。例如:

<Box sx={{ display: { xs: 'none', sm: 'block' } }}>
  {navItems.map((item) => (
    <Button key={item} sx={{ color: '#fff' }}>
      {item}
    </Button>
  ))}
</Box>

在上面的代码中,我们在屏幕较小(xs)时隐藏导航按钮,较大(sm)时则显示。

7. 完整代码

最终的完整代码如下:

function DrawerAppBar(props) {
  const { window } = props;
  const [mobileOpen, setMobileOpen] = React.useState(false);

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

  const drawer = (
    <Box onClick={handleDrawerToggle} sx={{ textAlign: 'center' }}>
      <Typography variant="h6" sx={{ my: 2 }}>
        MUI
      </Typography>
      <Divider />
      <List>
        {navItems.map((item) => (
          <ListItem key={item} disablePadding>
            <ListItemButton sx={{ textAlign: 'center' }}>
              <ListItemText primary={item} />
            </ListItemButton>
          </ListItem>
        ))}
      </List>
    </Box>
  );

  const container = window !== undefined ? () => window().document.body : undefined;

  return (
    <Box sx={{ display: 'flex' }}>
      <CssBaseline />
      <AppBar component="nav">
        <Toolbar>
          <IconButton
            color="inherit"
            aria-label="open drawer"
            edge="start"
            onClick={handleDrawerToggle}
            sx={{ mr: 2, display: { sm: 'none' } }}
          >
            <MenuIcon />
          </IconButton>
          <Typography
            variant="h6"
            component="div"
            sx={{ flexGrow: 1, display: { xs: 'none', sm: 'block' } }}
          >
            MUI
          </Typography>
          <Box sx={{ display: { xs: 'none', sm: 'block' } }}>
            {navItems.map((item) => (
              <Button key={item} sx={{ color: '#fff' }}>
                {item}
              </Button>
            ))}
          </Box>
        </Toolbar>
      </AppBar>
      <nav>
        <Drawer
          container={container}
          variant="temporary"
          open={mobileOpen}
          onClose={handleDrawerToggle}
          ModalProps={{
            keepMounted: true,
          }}
          sx={{
            display: { xs: 'block', sm: 'none' },
            '& .MuiDrawer-paper': { boxSizing: 'border-box', width: drawerWidth },
          }}
        >
          {drawer}
        </Drawer>
      </nav>
      <Box component="main" sx={{ p: 3 }}>
        <Toolbar />
        <Typography paragraph>
          内容可以自定义填充,这里是一些示例文本,用于展示页面布局效果。
        </Typography>
      </Box>
    </Box>
  );
}

三、总结

通过 App BarDrawer 的结合,我们可以轻松实现一个响应式的导航系统,确保在不同屏幕尺寸下都有良好的用户体验。在桌面端,导航项直接显示在 App Bar 上;而在移动端,导航项则被收纳在 Drawer 中,用户可以通过点击汉堡菜单来打开侧边栏。这种设计不仅节省了屏幕空间,还保持了良好的导航体验。

推荐:


在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Peter-Lu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值