You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React MUI X Data Grid选中项Chip展开/收起功能异常求助

React MUI X Data Grid 选中项Chip展示"More"时机异常排查

问题原因

你遇到的问题本质是硬编码或不准确的宽度估算导致的:原逻辑可能用固定数量作为显示"More"的阈值,而非根据容器实际可用宽度、每个Chip的真实渲染宽度(含间距、内边距)动态计算,所以实际要选到第4项才触发,和预期不符。

解决方案核心思路

  1. 获取真实DOM宽度:用useRef获取Chip容器和每个Chip的DOM元素,实时计算实际宽度
  2. 动态计算可容纳数量:结合容器可用宽度、每个Chip的宽度(含间距)、"More"按钮的预留宽度,算出能显示的最大Chip数量
  3. 响应窗口变化:监听窗口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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 16:33:14