React MUI X Data Grid选中项Chip展开/收起功能异常求助
React MUI X Data Grid 选中项Chip展示"More"时机异常排查
问题原因
你遇到的问题本质是硬编码或不准确的宽度估算导致的:原逻辑可能用固定数量作为显示"More"的阈值,而非根据容器实际可用宽度、每个Chip的真实渲染宽度(含间距、内边距)动态计算,所以实际要选到第4项才触发,和预期不符。
解决方案核心思路
- 获取真实DOM宽度:用
useRef获取Chip容器和每个Chip的DOM元素,实时计算实际宽度 - 动态计算可容纳数量:结合容器可用宽度、每个Chip的宽度(含间距)、"More"按钮的预留宽度,算出能显示的最大Chip数量
- 响应窗口变化:监听窗口resize事件,重新计算可显示数量,保证适配不同屏幕尺寸
核心代码修改示例
import { useRef, useEffect, useState } from 'react'; import { DataGrid } from '@mui/x-data-grid'; import Chip from '@mui/material/Chip'; export default function Demo() { const [selectedRows, setSelectedRows] = useState<any[]>([]); const [visibleChipsCount, setVisibleChipsCount] = useState(0); const [showAll, setShowAll] = useState(false); const chipsContainerRef = useRef<HTMLDivElement>(null); const chipRefs = useRef<(HTMLDivElement | null)[]>([]); const columns = [ { field: 'id', headerName: 'ID', width: 70 }, { field: 'firstName', headerName: 'First name', width: 130 }, { field: 'lastName', headerName: 'Last name', width: 130 }, { field: 'age', headerName: 'Age', type: 'number', width: 90 }, ]; const rows = [ { id: 1, lastName: 'Snow', firstName: 'Jon', age: 35 }, { id: 2, lastName: 'Lannister', firstName: 'Cersei', age: 42 }, { id: 3, lastName: 'Lannister', firstName: 'Jaime', age: 45 }, { id: 4, lastName: 'Stark', firstName: 'Arya', age: 16 }, { id: 5, lastName: 'Targaryen', firstName: 'Daenerys', age: null }, ]; useEffect(() => { const calculateVisibleChips = () => { if (!chipsContainerRef.current) return; // 获取容器总宽度 const containerWidth = chipsContainerRef.current.offsetWidth; let totalWidth = 0; let count = 0; // 预留"+N More"/"Hide"按钮的宽度(可根据实际样式调整) const actionButtonWidth = 100; const availableWidth = containerWidth - actionButtonWidth; // 逐个累加Chip宽度,直到超过可用空间 for (let i = 0; i < selectedRows.length; i++) { const chipEl = chipRefs.current[i]; if (!chipEl) continue; // 加上Chip的margin间距,保证计算准确 const chipTotalWidth = chipEl.offsetWidth + 8; if (totalWidth + chipTotalWidth <= availableWidth) { totalWidth += chipTotalWidth; count++; } else { break; } } setVisibleChipsCount(count); }; // 初始化计算+监听窗口 resize calculateVisibleChips(); window.addEventListener('resize', calculateVisibleChips); return () => window.removeEventListener('resize', calculateVisibleChips); }, [selectedRows]); const handleRowSelectionModelChange = (ids: number[]) => { const selected = ids.map(id => rows.find(row => row.id === id)).filter(Boolean); setSelectedRows(selected as any[]); // 切换选中项时自动收起展开状态 setShowAll(false); }; return ( <div style={{ height: 400, width: '100%' }}> <div ref={chipsContainerRef} style={{ display: 'flex', gap: 8, padding: 16, flexWrap: 'nowrap', overflow: 'hidden' }} > {/* 根据showAll状态决定显示全部还是可见数量的Chip */} {(showAll ? selectedRows : selectedRows.slice(0, visibleChipsCount)).map((row, idx) => ( <div key={row.id} ref={el => chipRefs.current[idx] = el}> <Chip label={`${row.firstName} ${row.lastName}`} onDelete={() => { const newSelected = selectedRows.filter(r => r.id !== row.id); setSelectedRows(newSelected); }} /> </div> ))} {/* 显示"+N More"按钮 */} {selectedRows.length > visibleChipsCount && !showAll && ( <Chip label={`+${selectedRows.length - visibleChipsCount} More`} onClick={() => setShowAll(true)} variant="outlined" /> )} {/* 显示"Hide"按钮 */} {showAll && ( <Chip label="Hide" onClick={() => setShowAll(false)} variant="outlined" /> )} </div> <DataGrid rows={rows} columns={columns} checkboxSelection onRowSelectionModelChange={handleRowSelectionModelChange} /> </div> ); }
关键修改点说明
- 新增
chipsContainerRef和chipRefs,用于获取容器和每个Chip的真实DOM宽度 - 动态计算逻辑替代固定阈值,确保"More"按钮在空间不足时及时出现
- 监听窗口resize事件,保证在窗口尺寸变化时重新计算
- 切换选中项时自动收起展开状态,提升用户体验
内容的提问来源于stack exchange,提问作者Narendra Jadhav
相关产品推荐
相关产品推荐

