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

MUI DataGrid展开行异常:列未合并且内容不显示

MUI DataGrid 展开详情行问题解决

我用MUI的DataGrid展示任务列表,想实现点击任务行后在下方显示可展开的详情行。现在尝试在选中行下方加一行跨列的行显示消息,但遇到两个问题:

  • 详情行显示不符合预期;
  • 能看到红色背景,但列没合并,消息也不显示。

我的当前代码:

"use client";

import * as React from "react";
import { DataGrid } from "@mui/x-data-grid";
import Box from "@mui/material/Box";

export default function TaskTable({ tasks }) {
    const [expandedTaskId, setExpandedTaskId] = React.useState(null);

    // Colonnes pour les tâches
    const columns = [
        { field: "title", headerName: "Titre", width: 200 },
        { field: "description", headerName: "Description", width: 300 },
        { field: "status", headerName: "Statut", width: 120 },
        { field: "priority", headerName: "Priorité", width: 120 },
        { field: "startDate", headerName: "Date de début", width: 150 },
        { field: "dueDate", headerName: "Date de fin", width: 150 },
        { field: "createdAt", headerName: "Créé le", width: 150 },
        { field: "updatedAt", headerName: "Mis à jour le", width: 150 },
        {
            field: "files",
            headerName: "Fichiers",
            width: 200,
            renderCell: (params) => (
                <ul>
                    {(params.value || []).map((file, index) => (
                        <li key={index}>
                            <a href={file.url} target="_blank" rel="noopener noreferrer">
                                {file.name}
                            </a>
                        </li>
                    ))}
                </ul>
            ),
        },
    ];

    // Fonction pour afficher/masquer le panneau des sous-tâches
    const handleRowClick = (params) => {
        setExpandedTaskId((prevId) => (prevId === params.row.id ? null : params.row.id));
    };

    //  les lignes de la table principale incluant les lignes cachées pour les sous-tâches
    const rows = tasks.flatMap((task) => {
        const mainRow = {
            id: task._id,
            title: task.title,
            description: task.description,
            status: task.status,
            priority: task.priority,
            startDate: task.startDate ? new Date(task.startDate).toLocaleDateString() : "N/A",
            dueDate: task.dueDate ? new Date(task.dueDate).toLocaleDateString() : "N/A",
            createdAt: task.createdAt ? new Date(task.createdAt).toLocaleDateString() : "N/A",
            updatedAt: task.updatedAt ? new Date(task.updatedAt).toLocaleDateString() : "N/A",
            files: task.files || [],
        };

        // Si la tâche est développée, ajouter une ligne supplémentaire avec un texte
        if (task._id === expandedTaskId) {
            return [
                mainRow,
                {
                    id: `${task._id}-expanded`,
                    message: "Détails supplémentaires pour cette tâche",
                    isExpandedRow: true,
                    colSpan: columns.length,
                },
            ];
        }

        return [mainRow];
    });

    return (
        <Box sx={{ width: "100%" }}>
            <DataGrid
                rows={rows}
                columns={columns}
                pageSize={5}
                getRowId={(row) => row.id}
                onRowClick={(params) => {
                    if (!params.row.isExpandedRow) handleRowClick(params);
                }}
                getRowClassName={(params) =>
                    params.row.isExpandedRow ? "expanded-row" : ""
                }
                components={{
                    Row: (props) => (
                        <>
                            <props.components.Row {...props} />
                            {props.row.isExpandedRow && (
                                <Box
                                    sx={{
                                        pl: 2,
                                        width: "100%",
                                        bgcolor: "rgba(255, 0, 0, 0.1)",
                                        gridColumn: `span ${columns.length}`,

                                    }}
                                >
                                    <Box sx={{ padding: 1, color: "black" }}>
                                        <p>Test</p>
                                        {/* <p>{props.row.message}</p> */}
                                    </Box>
                                </Box>
                            )}
                        </>
                    ),
                }}
                sx={{
                    "& .MuiDataGrid-row.expanded-row": {
                        bgcolor: "rgba(255, 0, 0, 0.1)",
                        color: "black",
                        "& .MuiDataGrid-cell": {
                            display: "flex",
                            justifyContent: "center",
                            fontStyle: "italic",
                        },
                    },
                }}
            />
        </Box>
    );
}

问题原因分析

  • 你手动添加额外行+自定义Row组件的方式,不符合DataGrid的渲染逻辑:Row组件的内部布局是按列定义生成单元格,额外插入的Box会脱离原有布局,导致样式错乱。
  • 展开行的colSpan属性没有对应列定义的处理逻辑,无法实现列合并效果。

正确实现方案(官方推荐)

使用DataGrid内置的**detailPanel行展开功能**,无需手动拼接行,完美解决跨列和内容显示问题:

"use client";

import * as React from "react";
import { DataGrid } from "@mui/x-data-grid";
import Box from "@mui/material/Box";

export default function TaskTable({ tasks }) {
    const [expandedTaskId, setExpandedTaskId] = React.useState(null);

    // 任务列定义
    const columns = [
        { field: "title", headerName: "Titre", width: 200 },
        { field: "description", headerName: "Description", width: 300 },
        { field: "status", headerName: "Statut", width: 120 },
        { field: "priority", headerName: "Priorité", width: 120 },
        { field: "startDate", headerName: "Date de début", width: 150 },
        { field: "dueDate", headerName: "Date de fin", width: 150 },
        { field: "createdAt", headerName: "Créé le", width: 150 },
        { field: "updatedAt", headerName: "Mis à jour le", width: 150 },
        {
            field: "files",
            headerName: "Fichiers",
            width: 200,
            renderCell: (params) => (
                <ul>
                    {(params.value || []).map((file, index) => (
                        <li key={index}>
                            <a href={file.url} target="_blank" rel="noopener noreferrer">
                                {file.name}
                            </a>
                        </li>
                    ))}
                </ul>
            ),
        },
    ];

    // 点击行切换展开状态
    const handleRowClick = (params) => {
        setExpandedTaskId(prevId => prevId === params.row.id ? null : params.row.id);
    };

    // 转换任务数据格式
    const rows = tasks.map(task => ({
        id: task._id,
        title: task.title,
        description: task.description,
        status: task.status,
        priority: task.priority,
        startDate: task.startDate ? new Date(task.startDate).toLocaleDateString() : "N/A",
        dueDate: task.dueDate ? new Date(task.dueDate).toLocaleDateString() : "N/A",
        createdAt: task.createdAt ? new Date(task.createdAt).toLocaleDateString() : "N/A",
        updatedAt: task.updatedAt ? new Date(task.updatedAt).toLocaleDateString() : "N/A",
        files: task.files || [],
    }));

    // 渲染详情面板内容
    const renderDetailPanel = ({ row }) => (
        <Box sx={{ p: 3, bgcolor: "rgba(255, 0, 0, 0.1)" }}>
            <p>{`Détails supplémentaires pour la tâche: ${row.title}`}</p>
            {/* 可添加更多自定义详情内容,比如任务备注、历史记录等 */}
        </Box>
    );

    return (
        <Box sx={{ width: "100%" }}>
            <DataGrid
                rows={rows}
                columns={columns}
                pageSize={5}
                getRowId={(row) => row.id}
                onRowClick={handleRowClick}
                // 配置详情面板
                detailPanel={[
                    {
                        disableToggle: false,
                        getExpandedRowIds: () => expandedTaskId ? [expandedTaskId] : [],
                        render: renderDetailPanel,
                    },
                ]}
                // 可选:隐藏默认展开图标,完全通过点击行控制
                components={{
                    DetailPanelToggle: () => null,
                }}
            />
        </Box>
    );
}

关键修改说明

  1. 使用内置detailPanel:官方组件自动处理跨列布局,确保内容占满整行,无需手动拼接额外行。
  2. 精准控制展开状态:通过getExpandedRowIds关联expandedTaskId,实现点击行切换展开/收起。
  3. 灵活自定义详情:renderDetailPanel可自由渲染任意内容,样式控制更简单。
  4. 简化代码结构:移除了冗余的自定义Row组件和额外行生成逻辑,降低维护成本。

如果坚持要手动实现(不推荐),需:

  • 添加特殊列专门渲染展开行内容,同时设置其他列在展开行时隐藏;
  • 调整Row组件的布局逻辑,确保跨列元素嵌入DataGrid的单元格布局中。但这种方式易引发样式冲突,维护成本高。

内容的提问来源于stack exchange,提问作者Khaoula EL MOUANNISS

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 13:52:13