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> ); }
关键修改说明
- 使用内置
detailPanel:官方组件自动处理跨列布局,确保内容占满整行,无需手动拼接额外行。 - 精准控制展开状态:通过
getExpandedRowIds关联expandedTaskId,实现点击行切换展开/收起。 - 灵活自定义详情:
renderDetailPanel可自由渲染任意内容,样式控制更简单。 - 简化代码结构:移除了冗余的自定义Row组件和额外行生成逻辑,降低维护成本。
如果坚持要手动实现(不推荐),需:
- 添加特殊列专门渲染展开行内容,同时设置其他列在展开行时隐藏;
- 调整Row组件的布局逻辑,确保跨列元素嵌入DataGrid的单元格布局中。但这种方式易引发样式冲突,维护成本高。
内容的提问来源于stack exchange,提问作者Khaoula EL MOUANNISS
相关产品推荐
相关产品推荐

