這個套件應用的範圍很廣,之前講解過的 Select 也是用這裡的 MenuItem 來替換原本的 option,官方文件
預設的情況下是從點擊位子的 element 上方開啟選單,可以透過 anchorOrigin 屬性修改開啟選單的位置,當靠近螢幕邊緣時,選單會垂直重新對齊以確保所有選項都完全可見。
理想情況下,選擇一個選項應該立即提交該選項並關閉選單。
因為不用像對話框那樣,影響整個頁面來顯示資訊,所以交互性較佳,用途也比較廣泛:
// in export function
const [anchorEl, setAnchorEl] = React.useState(null);
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
// in return
<Button aria-controls="simple-menu" aria-haspopup="true" onClick={handleClick}>
Open Menu
</Button>
<Menu
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
<MenuItem onClick={handleClose}>Profile</MenuItem>
<MenuItem onClick={handleClose}>My account</MenuItem>
<MenuItem onClick={handleClose}>Logout</MenuItem>
</Menu>
如果用於項目選擇,打開時,一般選單會嘗試將當前選中的選項與錨點垂直對齊,預設焦點將放在選中的選項上。
範例中選擇的選項是使用 selected 屬性(ListItem)設置的。
要使用選定的選項而不影響選單的預設焦點或垂直定位,請將 variant 屬性設置為 menu。
// 先定義選項
const options = [
'去冰',
'微冰',
'少冰',
'正常',
];
// in export function
const [anchorEl, setAnchorEl] = React.useState(null);
// 設定options的對應位置
const [selectedIndex, setSelectedIndex] = React.useState(1);
const handleClickListItem = (event) => {
setAnchorEl(event.currentTarget);
};
const handleMenuItemClick = (event, index) => {
setSelectedIndex(index);
setAnchorEl(null);
};
const handleClose = () => {
setAnchorEl(null);
};
<div className={classes.root}>
<List component="nav" aria-label="Device settings">
<ListItem
button
aria-haspopup="true"
aria-controls="lock-menu"
aria-label="手搖飲料冰度"
onClick={handleClickListItem}
>
<ListItemText
primary="手搖飲料冰度"
secondary={options[selectedIndex]}
/>
</ListItem>
</List>
<Menu
id="lock-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
{options.map((option, index) => (
<MenuItem
key={option}
disabled={index === 0}
selected={index === selectedIndex}
onClick={(event) => handleMenuItemClick(event, index)}
>
{option}
</MenuItem>
))}
</Menu>
</div>
Menu 組件在內部使用 Popover 組件,但是,您可能希望使用不同的定位策略,或者不阻止滾動,為了滿足這些需求,官網公開了一個您可以組合的 MenuList 組件,在此示例中使用 Popper。
// in export function
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);
}
};
const prevOpen = React.useRef(open);
React.useEffect(() => {
if (prevOpen.current === true && open === false) {
anchorRef.current.focus();
}
prevOpen.current = open;
}, [open]);
// in return
<div className={classes.root}>
<Paper className={classes.paper}>
<MenuList>
<MenuItem>Profile</MenuItem>
<MenuItem>My account</MenuItem>
<MenuItem>Logout</MenuItem>
</MenuList>
</Paper>
<div>
<Button
ref={anchorRef}
aria-controls={open ? 'menu-list-grow' : undefined}
aria-haspopup="true"
onClick={handleToggle}
>
Toggle Menu Grow
</Button>
<Popper
open={open}
anchorEl={anchorRef.current}
role={undefined}
transition
disablePortal
>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={
{ transformOrigin: placement === 'bottom'
? 'center top'
: 'center bottom'
}
}
>
<Paper>
<ClickAwayListener onClickAway={handleClose}>
<MenuList
autoFocusItem={open}
id="menu-list-grow"
onKeyDown={handleListKeyDown}
>
<MenuItem onClick={handleClose}>Profile</MenuItem>
<MenuItem onClick={handleClose}>My account</MenuItem>
<MenuItem onClick={handleClose}>Logout</MenuItem>
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</div>
</div>
如果選單的高度阻止顯示所有選項,則選單可以在內部滾動。
// 設一組較多的選項組
const options = [
'None',
'Atria',
'Callisto',
'Dione',
'Ganymede',
'Hangouts Call',
'Luna',
'Oberon',
'Phobos',
'Pyxis',
'Sedna',
'Titania',
'Triton',
'Umbriel',
];
// in export function
const [anchorEl, setAnchorEl] = React.useState(null);
const open = Boolean(anchorEl);
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
// in return
<div>
<IconButton
aria-label="more"
aria-controls="long-menu"
aria-haspopup="true"
onClick={handleClick}
>
<MoreVertIcon />
</IconButton>
<Menu
id="long-menu"
anchorEl={anchorEl}
keepMounted
open={open}
onClose={handleClose}
PaperProps={{
style: {
maxHeight: 216,
width: '20ch',
},
}}
>
{options.map((option) => (
<MenuItem
key={option}
selected={option === 'Pyxis'}
onClick={handleClose}
>
{option}
</MenuItem>
))}
</Menu>
</div>
如果選項內容很長的話可以透過 Typography 組件去限制:
<Paper style={{ width: 230 }}>
<MenuList>
<MenuItem>
<ListItemIcon>
<SendIcon fontSize="small" />
</ListItemIcon>
<Typography variant="inherit">A short message</Typography>
</MenuItem>
<MenuItem>
<ListItemIcon>
<PriorityHighIcon fontSize="small" />
</ListItemIcon>
<Typography variant="inherit">A very long text that overflows</Typography>
</MenuItem>
<MenuItem>
<ListItemIcon>
<DraftsIcon fontSize="small" />
</ListItemIcon>
<Typography variant="inherit" noWrap>
A very long text that overflows
</Typography>
</MenuItem>
</MenuList>
</Paper>
那麼今天的內容就講解到這裡,比較進階和自訂話的方法各位可以去官方文件查詢,明天會講解 AppBar 組件。