如何基于选项属性用MUI Autocomplete渲染两个并排结果列表?
解决方案
要实现按type属性分隔为并排双列表的搜索结果,核心思路是自定义Autocomplete的下拉面板(Paper),手动对选项分组并通过Flex布局实现并排展示,同时保留原有的交互逻辑。以下是具体修改步骤和代码:
1. 导入所需MUI组件
确保你已经导入了这些组件(如果没有的话):
import { Paper, Box, Typography, List, ListItem, ListItemText } from '@mui/material';
2. 分组处理选项数据
在组件内部,将原options按type拆分为两个数组:
const bikeOptions = options.filter(opt => opt.type === bikeSmooveboxType); const stationOptions = options.filter(opt => opt.type === stationTransmiterType);
3. 自定义下拉面板(renderPaper)
给Autocomplete添加renderPaper属性,替换默认的垂直列表布局,改为并排双列:
<Autocomplete freeSolo={true} id="equipment-searchbar" onOpen={() => setOpen(true)} onClose={() => setOpen(false)} clearOnBlur={false} isOptionEqualToValue={(option, value) => option.name === value.name} getOptionLabel={(option) => option.title || ''} filterOptions={x => x} options={options} // 移除原来的groupBy,改为手动分组 onInputChange={onInputChange} open={open} onChange={(event: any, option: any) => { let searchData = (document.getElementById("equipment-searchbar") as HTMLInputElement).value if (option !== null && option.globalSearch !== true) { switch (option.type) { case bikeSmooveboxType: redirect("bike/" + option.title) break; case stationTransmiterType: redirect("station/" + option.code) break; } } }} loading={loading} // 新增:自定义下拉面板 renderPaper={(params) => { const { inputValue } = params; // 处理freeSolo模式下的自定义输入选项 const hasFreeSoloOption = freeSolo && inputValue !== '' && !options.some(opt => getOptionLabel(opt) === inputValue); return ( <Paper {...params} sx={{ display: 'flex', gap: 2, p: 2, maxWidth: 800, flexWrap: 'wrap' // 小屏幕自动换行 }}> {/* 自由输入选项(可选) */} {hasFreeSoloOption && ( <Box width="100%" mb={2}> <Typography variant="subtitle2" fontWeight="bold" mb={1}> 搜索内容 </Typography> <ListItem button {...params.getOptionProps({ option: { title: inputValue, globalSearch: true } })} sx={{ backgroundColor: params.focusedOption?.title === inputValue ? 'rgba(0,0,0,0.04)' : 'transparent' }} > <ListItemText primary={`"${inputValue}"`} /> </ListItem> </Box> )} {/* 第一列:自行车设备 */} <Box flex={1} minWidth={200}> <Typography variant="subtitle2" fontWeight="bold" mb={1}> 自行车设备 </Typography> <List> {bikeOptions.map((option) => ( <ListItem key={option.name || option.title} button {...params.getOptionProps({ option })} sx={{ backgroundColor: params.focusedOption === option ? 'rgba(0,0,0,0.04)' : 'transparent', '&:hover': { backgroundColor: 'rgba(0,0,0,0.04)' } }} > <ListItemText primary={option.title} /> </ListItem> ))} </List> </Box> {/* 第二列:站点设备 */} <Box flex={1} minWidth={200}> <Typography variant="subtitle2" fontWeight="bold" mb={1}> 站点设备 </Typography> <List> {stationOptions.map((option) => ( <ListItem key={option.name || option.code} button {...params.getOptionProps({ option })} sx={{ backgroundColor: params.focusedOption === option ? 'rgba(0,0,0,0.04)' : 'transparent', '&:hover': { backgroundColor: 'rgba(0,0,0,0.04)' } }} > <ListItemText primary={option.title} /> </ListItem> ))} </List> </Box> </Paper> ); }} renderInput={(params) => ( <TextField className="inputRounded" variant="outlined" label="Rechercher dans les équipements" {...params} InputProps={{ ...params.InputProps, endAdornment: ( <React.Fragment> <SearchIcon/> {params.InputProps.endAdornment} </React.Fragment> ), }} /> )} />
关键说明
params.getOptionProps({ option }):自动绑定选项的点击、选中、键盘导航等交互逻辑,确保和默认Autocomplete行为一致。- Flex布局:通过
display: flex让两列并排,flex:1实现宽度平分,minWidth保证小屏幕下的可读性。 - 高亮样式:通过
params.focusedOption判断当前聚焦的选项,设置和MUI默认一致的背景色。 - FreeSolo兼容:保留了自由输入的选项展示,确保原有功能不受影响。
内容的提问来源于stack exchange,提问作者Zantyor2
相关产品推荐
相关产品推荐

