如何基于Material UI开发多级下拉选择器?附示例数据
基于Material UI的三级下拉选择器实现
以下是适配你提供的menuData数据源的三级嵌套下拉选择器实现,基于Material UI组件构建:
import React, { useState } from 'react'; import { Select, MenuItem, List, Collapse, Typography, Box } from '@mui/material'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import ExpandLessIcon from '@mui/icons-material/ExpandLess'; const menuData = [ { mainItem: "FRESHWATER FISH", mainId: "main001", subMenu: [ { subId: "sub001", subItem: "Discus", }, { subId: "sub002", subItem: "Gold Fish", cateItem: [ { cateId: "cate001", cateItem: "Oranda Goldfish", }, { cateId: "cate002", cateItem: "Black Oranda Goldfish", }, ], }, ], }, { mainItem: "MARINE FISH", mainId: "main002", }, { mainItem: "FRESHWATER PLANTS", mainId: "main003", }, ]; const TieredSelect = () => { const [selectedValue, setSelectedValue] = useState(null); const [expandedMainIds, setExpandedMainIds] = useState(new Set()); const [expandedSubIds, setExpandedSubIds] = useState(new Set()); // 切换主菜单展开状态 const toggleMainExpand = (mainId) => { setExpandedMainIds(prev => { const newSet = new Set(prev); newSet.has(mainId) ? newSet.delete(mainId) : newSet.add(mainId); return newSet; }); }; // 切换子菜单展开状态 const toggleSubExpand = (subId) => { setExpandedSubIds(prev => { const newSet = new Set(prev); newSet.has(subId) ? newSet.delete(subId) : newSet.add(subId); return newSet; }); }; // 处理选项选中 const handleSelect = (value) => { setSelectedValue(value); }; // 匹配选中值的显示文本 const getDisplayText = (selected) => { if (!selected) return '请选择'; let displayText = selected; menuData.forEach(main => { if (main.mainId === selected) displayText = main.mainItem; else if (main.subMenu) { main.subMenu.forEach(sub => { if (sub.subId === selected) displayText = `${main.mainItem} > ${sub.subItem}`; else if (sub.cateItem) { sub.cateItem.forEach(cate => { if (cate.cateId === selected) displayText = `${main.mainItem} > ${sub.subItem} > ${cate.cateItem}`; }); } }); } }); return displayText; }; return ( <Box sx={{ minWidth: 240 }}> <Select value={selectedValue || ''} onChange={(e) => handleSelect(e.target.value)} displayEmpty sx={{ width: '100%' }} renderValue={(selected) => <Typography>{getDisplayText(selected)}</Typography>} > <MenuItem value="" disabled>请选择</MenuItem> <List> {menuData.map(main => ( <React.Fragment key={main.mainId}> <MenuItem onClick={() => main.subMenu ? toggleMainExpand(main.mainId) : handleSelect(main.mainId)} sx={{ justifyContent: 'space-between' }} > <Typography>{main.mainItem}</Typography> {main.subMenu && ( expandedMainIds.has(main.mainId) ? <ExpandLessIcon /> : <ExpandMoreIcon /> )} </MenuItem> {main.subMenu && expandedMainIds.has(main.mainId) && ( <Collapse in timeout="auto" unmountOnExit> <List component="div" disablePadding sx={{ pl: 4 }}> {main.subMenu.map(sub => ( <React.Fragment key={sub.subId}> <MenuItem onClick={() => sub.cateItem ? toggleSubExpand(sub.subId) : handleSelect(sub.subId)} sx={{ justifyContent: 'space-between' }} > <Typography>{sub.subItem}</Typography> {sub.cateItem && ( expandedSubIds.has(sub.subId) ? <ExpandLessIcon /> : <ExpandMoreIcon /> )} </MenuItem> {sub.cateItem && expandedSubIds.has(sub.subId) && ( <Collapse in timeout="auto" unmountOnExit> <List component="div" disablePadding sx={{ pl: 4 }}> {sub.cateItem.map(cate => ( <MenuItem key={cate.cateId} value={cate.cateId} onClick={() => handleSelect(cate.cateId)} > <Typography>{cate.cateItem}</Typography> </MenuItem> ))} </List> </Collapse> )} </React.Fragment> ))} </List> </Collapse> )} </React.Fragment> ))} </List> </Select> </Box> ); }; export default TieredSelect;
实现说明
- 支持三级菜单的展开/收起,通过
Collapse组件实现平滑过渡 - 选中后自动拼接完整层级路径文本展示
- 点击无下级菜单的选项直接完成选中,有下级菜单的选项则切换展开状态
- 使用
Set管理展开菜单ID,避免状态冲突
内容的提问来源于stack exchange,提问作者shiran sandaruwan
相关产品推荐
相关产品推荐

