文章目录
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 Bar
和 Drawer
组件,构建一个可响应不同屏幕尺寸的导航系统。对于桌面端,我们将显示一个水平排列的导航按钮,而在移动端,我们将隐藏按钮,转而展示一个 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 Bar
与 Drawer
的结合,我们可以轻松实现一个响应式的导航系统,确保在不同屏幕尺寸下都有良好的用户体验。在桌面端,导航项直接显示在 App Bar
上;而在移动端,导航项则被收纳在 Drawer
中,用户可以通过点击汉堡菜单来打开侧边栏。这种设计不仅节省了屏幕空间,还保持了良好的导航体验。
推荐: