如何根据Autocomplete宽度动态设置limitTags的值?
MUI Autocomplete 实现标签宽度自适应折叠+点击展开全部选中项
要实现标签占满容器宽度时自动折叠为+n,点击时展示全部选中项的效果,需要替换默认的limitTags固定数量逻辑,改用自定义标签渲染和宽度测量的方式。以下是基于你现有代码的修改方案:
核心思路
- 监听Autocomplete容器宽度,动态计算可容纳的标签数量
- 自定义
renderTags方法,根据宽度判断显示标签或折叠为+n - 通过聚焦/失焦事件控制是否展开全部标签
修改后的完整代码
import { useState, useRef } from 'react'; import { Autocomplete, TextField, Chip } from '@mui/material'; const CustomFilterAutocomplete = ({ dropDownOptions, availableWidth = 600 }) => { const [value, setValue] = useState([]); const [inputValue, setInputValue] = useState(''); const [isExpanded, setIsExpanded] = useState(false); const containerRef = useRef(null); return ( <Autocomplete multiple freeSolo id='multiple-dynamic-limit-tags' options={dropDownOptions.map((option) => option.title)} value={value} inputValue={inputValue} onChange={(event, newValue) => { setValue([...newValue]); }} onInputChange={(event, newInputValue) => { setInputValue(newInputValue); }} getOptionLabel={(option) => option} ref={containerRef} onFocus={() => setIsExpanded(true)} onBlur={() => setIsExpanded(false)} renderTags={(valueList, getTagProps) => { if (!containerRef.current || valueList.length === 0) return null; const containerWidth = containerRef.current.offsetWidth; const inputElement = containerRef.current.querySelector('input'); // 预留输入框的最小宽度,可根据实际样式调整 const inputMinWidth = inputElement ? inputElement.offsetWidth : 120; let totalUsedWidth = inputMinWidth; const visibleTags = []; // 模拟标签样式并计算每个标签的实际宽度 const getTagWidth = (label) => { const tempTag = document.createElement('span'); // 复制MUI Chip的默认内边距、间距等样式,保证宽度计算准确 tempTag.style.cssText = ` display: inline-block; margin-right: 8px; padding: 6px 12px; border-radius: 16px; font-size: 0.875rem; font-family: Roboto, Helvetica, Arial, sans-serif; `; tempTag.textContent = label; document.body.appendChild(tempTag); const width = tempTag.offsetWidth; document.body.removeChild(tempTag); return width; }; // 遍历标签,计算可容纳的数量 for (let i = 0; i < valueList.length; i++) { const tagWidth = getTagWidth(valueList[i]); if (totalUsedWidth + tagWidth > containerWidth) break; totalUsedWidth += tagWidth; visibleTags.push(valueList[i]); } // 展开状态下显示全部标签 if (isExpanded) { return valueList.map((option, index) => ( <Chip label={option} {...getTagProps({ index })} key={index} size="small" /> )); } // 折叠状态下显示可见标签和+n const remainingCount = valueList.length - visibleTags.length; return [ ...visibleTags.map((option, index) => ( <Chip label={option} {...getTagProps({ index })} key={index} size="small" /> )), remainingCount > 0 && ( <Chip label={`+${remainingCount}`} key="remaining" size="small" disabled /> ), ]; }} renderInput={(params) => ( <TextField {...params} label='Filters' /> )} sx={{ width: availableWidth }} /> ); }; export default CustomFilterAutocomplete;
关键说明
- 宽度测量:通过临时创建标签元素并计算其宽度,模拟实际渲染后的尺寸,确保判断准确
- 展开/折叠控制:利用
onFocus和onBlur事件切换isExpanded状态,点击输入框时自动展开全部标签 - 样式一致性:临时标签复制了MUI Chip的默认样式,避免宽度计算偏差
- freeSolo兼容:保留了原有的自由输入逻辑,不影响自定义标签的添加
内容的提问来源于stack exchange,提问作者Payas Hasteer
相关产品推荐
相关产品推荐

