文章目录
Material-UI 是 React 框架中最流行的 UI 库之一,它提供了众多可复用的组件。Menu 组件是应用中常见的下拉菜单功能,它基于 Popover 组件进行定位,允许用户自定义位置及行为。本文将详细介绍 Menu 组件中的 Positioned Menu 和 MenuList Composition,并展示如何在不同场景下灵活运用这些组件。
一、Positioned Menu 组件概述
1. 什么是 Positioned Menu?
Positioned Menu
是 Material-UI 中基于 Popover 组件实现的菜单,允许用户根据特定的锚点(anchor)来定位菜单。这个功能对于复杂的 UI 布局非常有用,能够在不同的按钮或界面元素上展示菜单,并控制菜单的打开位置。
2. Positioned Menu 的主要功能
通过设置 anchorOrigin
和 transformOrigin
属性,Positioned Menu
允许开发者定义菜单相对于触发按钮的具体位置。这些属性可以分别定义菜单的起点和变换起点,例如将菜单显示在按钮的上方或左侧。
二、Positioned Menu 的基本用法
以下是一个使用 Positioned Menu
的示例:
import * as React from 'react';
import Button from '@mui/material/Button';
import Menu from '@mui/material/Menu';
import MenuItem from '@mui/material/MenuItem';
export default function PositionedMenu() {
const [anchorEl, setAnchorEl] = React.useState(null);
const open = Boolean(anchorEl);
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
<div>
<Button
id="demo-positioned-button"
aria-controls={open ? 'demo-positioned-menu' : undefined}
aria-haspopup="true"
aria-expanded={open ? 'true' : undefined}
onClick={handleClick}
>
Dashboard
</Button>
<Menu
id="demo-positioned-menu"
aria-labelledby="demo-positioned-button"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
anchorOrigin={{
vertical: 'top',
horizontal: 'left',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'left',
}}
>
<MenuItem onClick={handleClose}>Profile</MenuItem>
<MenuItem onClick={handleClose}>My account</MenuItem>
<MenuItem onClick={handleClose}>Logout</MenuItem>
</Menu>
</div>
);
}
3. anchorOrigin 和 transformOrigin 的作用
在这个例子中,anchorOrigin
和 transformOrigin
是控制菜单显示位置的两个关键属性:
- anchorOrigin:定义菜单的起始位置相对于锚点的位置。这里的设置是
top
和left
,意味着菜单会从锚点的左上角弹出。 - transformOrigin:定义菜单的内容从哪里开始展开。在示例中,菜单内容从左上角展开。
4. Positioned Menu 的优势
- 灵活性高:通过配置
anchorOrigin
和transformOrigin
,开发者可以灵活地控制菜单的展开方式和位置。 - 易于整合:Positioned Menu 基于 Popover 组件,直接集成于现有的 Material-UI 项目中,无需额外复杂的设置。
三、MenuList Composition 组件详解
1. 什么是 MenuList Composition?
在某些场景下,默认的 Menu 组件基于 Popover 实现,可能不符合所有的设计需求,特别是在需要不同的定位策略或避免滚动阻塞时。这时,MenuList
组件就派上了用场。MenuList
是一个独立的菜单列表组件,它提供了更灵活的控制和自定义选项,开发者可以根据需要组合其他组件,比如 Popper
来实现不同的菜单展现方式。
2. MenuList Composition 的功能和用法
以下是一个使用 MenuList
组件结合 Popper
实现自定义菜单的例子:
import * as React from 'react';
import Button from '@mui/material/Button';
import ClickAwayListener from '@mui/material/ClickAwayListener';
import Grow from '@mui/material/Grow';
import Paper from '@mui/material/Paper';
import Popper from '@mui/material/Popper';
import MenuItem from '@mui/material/MenuItem';
import MenuList from '@mui/material/MenuList';
import Stack from '@mui/material/Stack';
export default function MenuListComposition() {
const [open, setOpen] = React.useState(false);
const anchorRef = React.useRef(null);
const handleToggle = () => {
setOpen((prevOpen) => !prevOpen);
};
const handleClose = (event) => {
if (anchorRef.current && anchorRef.current.contains(event.target)) {
return;
}
setOpen(false);
};
function handleListKeyDown(event) {
if (event.key === 'Tab') {
event.preventDefault();
setOpen(false);
} else if (event.key === 'Escape') {
setOpen(false);
}
}
// return focus to the button when we transitioned from !open -> open
const prevOpen = React.useRef(open);
React.useEffect(() => {
if (prevOpen.current === true && open === false) {
anchorRef.current.focus();
}
prevOpen.current = open;
}, [open]);
return (
<Stack direction="row" spacing={2}>
<div>
<Button
ref={anchorRef}
id="composition-button"
aria-controls={open ? 'composition-menu' : undefined}
aria-expanded={open ? 'true' : undefined}
aria-haspopup="true"
onClick={handleToggle}
>
Dashboard
</Button>
<Popper
open={open}
anchorEl={anchorRef.current}
role={undefined}
placement="bottom-start"
transition
disablePortal
>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{
transformOrigin:
placement === 'bottom-start' ? 'left top' : 'left bottom',
}}
>
<Paper>
<ClickAwayListener onClickAway={handleClose}>
<MenuList
autoFocusItem={open}
id="composition-menu"
aria-labelledby="composition-button"
onKeyDown={handleListKeyDown}
>
<MenuItem onClick={handleClose}>Profile</MenuItem>
<MenuItem onClick={handleClose}>My account</MenuItem>
<MenuItem onClick={handleClose}>Logout</MenuItem>
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</div>
</Stack>
);
}
3. MenuList Composition 的关键点
- 独立菜单控制:
MenuList
允许开发者更精细地控制菜单的行为,不再依赖 Popover 的默认功能,适合需要更多定制的场景。 - 结合 Popper:通过与
Popper
组件结合,MenuList
可以实现与Popover
不同的定位策略,避免了传统 Popover 对滚动的阻塞效果。
4. 菜单的关闭与键盘控制
在该示例中,ClickAwayListener
用于监控用户点击菜单外部的事件,以便关闭菜单。同时,通过监听键盘事件(如 Tab
或 Escape
键),开发者可以进一步增强用户的交互体验。这样可以保证在菜单关闭时,焦点重新回到触发按钮上,提升了可访问性。
四、Positioned Menu 与 MenuList Composition 的对比与适用场景
- Positioned Menu:适合大多数情况下的简单菜单展示,基于 Popover 定位,易于实现和控制。
- MenuList Composition:更适合复杂的场景,特别是在需要自定义定位或避免滚动阻塞时,通过
Popper
和MenuList
的组合可以实现灵活的布局和行为控制。
五、总结
Material-UI 中的 Positioned Menu
和 MenuList Composition
组件为开发者提供了强大的菜单控制功能。通过灵活运用这些组件,开发者可以轻松实现各种复杂的菜单布局和交互逻辑,满足不同的设计需求。
推荐: