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

Mui DataGrid详情列:实现超8行显示展开按钮及行数判断

MUI DataGrid详情列折叠/展开实现(仅内容超8行时显示按钮)

需求

  • 详情列默认最多显示8行内容
  • 内容超出8行时,显示「显示更多」按钮,点击后展开全部内容;展开后可切换回收起状态

当前问题

已通过WebkitLineClamp: 8实现默认8行限制,也想到用状态记录展开行ID来切换显示行数,但无法判断内容是否超过8行,导致按钮始终显示,不符合需求。

解决方案

判断内容是否超行的核心逻辑

通过对比元素的实际内容高度和限制8行后的高度:

  • 渲染一个与显示元素样式完全一致但不限制行数的隐藏元素,获取其完整高度
  • 获取限制8行的显示元素的高度
  • 若隐藏元素高度 > 显示元素高度,说明内容超出8行,显示按钮

完整代码实现

import { useState, useRef, useEffect } from 'react';
import { DataGrid, GridColDef } from '@mui/x-data-grid';
import { Box, Typography, Button } from '@mui/material';
// 假设t是你的国际化函数
import { t } from './your-i18n-module';

const YourComponent = () => {
  // 记录展开的行ID集合
  const [expandedRowIds, setExpandedRowIds] = useState<Set<number>>(new Set());
  // 保留原有分页状态
  const [currentPage, setCurrentPage] = useState(0);
  const [pageSize, setPageSize] = useState(25);
  const mockData = [/* 你的业务数据 */];

  const columns: GridColDef[] = [
    {
      field: 'title',
      headerName: t`Title`,
      flex: 1,
    },
    {
      field: 'details',
      headerName: t`Details`,
      flex: 2,
      renderCell: ({ row }) => {
        const isExpanded = expandedRowIds.has(row.id);
        const visibleTextRef = useRef<HTMLDivElement>(null);
        const hiddenTextRef = useRef<HTMLDivElement>(null);
        const [showMore, setShowMore] = useState(false);

        useEffect(() => {
          if (visibleTextRef.current && hiddenTextRef.current) {
            // 对比高度判断内容是否超出行数
            setShowMore(hiddenTextRef.current.scrollHeight > visibleTextRef.current.clientHeight);
          }
        }, [row.details]);

        return (
          <Box sx={{ padding: 1, position: 'relative' }}>
            {/* 显示的文本,根据展开状态控制行数 */}
            <Typography
              ref={visibleTextRef}
              variant="body2"
              sx={{
                display: '-webkit-box',
                overflow: 'hidden',
                WebkitBoxOrient: 'vertical',
                WebkitLineClamp: isExpanded ? 'unset' : 8,
                lineHeight: 1.5, // 固定行高保证高度计算准确
              }}
            >
              {row.details}
            </Typography>
            {/* 隐藏的文本,用于获取完整内容高度 */}
            <Typography
              ref={hiddenTextRef}
              variant="body2"
              sx={{
                position: 'absolute',
                visibility: 'hidden',
                top: 0,
                left: 0,
                right: 0,
                lineHeight: 1.5, // 和显示文本保持一致样式
                whiteSpace: 'pre-wrap', // 确保换行逻辑一致
              }}
            >
              {row.details}
            </Typography>
            {/* 仅当内容超行时显示按钮 */}
            {showMore && (
              <Button
                sx={{ color: 'primary', padding: 0, margin: '8px 0 0' }}
                onClick={() => {
                  setExpandedRowIds(prev => {
                    const newSet = new Set(prev);
                    isExpanded ? newSet.delete(row.id) : newSet.add(row.id);
                    return newSet;
                  });
                }}
              >
                {isExpanded ? '收起' : '显示更多'}
              </Button>
            )}
          </Box>
        );
      },
    },
  ];

  return (
    <DataGrid
      sx={{
        border: 0,
        '& .MuiDataGrid-columnHeaders': { backgroundColor: '#F5F6F8' },
      }}
      isRowSelectable={() => false}
      autoHeight
      getRowHeight={() => 'auto'}
      loading={false}
      columns={columns}
      rows={mockData || []}
      rowCount={5}
      page={currentPage}
      onPageChange={(newPage) => setCurrentPage(newPage)}
      onPageSizeChange={setPageSize}
      pageSize={pageSize}
      rowsPerPageOptions={[25, 50, 100]}
    />
  );
};

export default YourComponent;

关键说明

  • 两个Typography必须保持完全一致的样式(行高、字体、宽度等),否则高度对比会出错
  • 使用useEffect监听row.details变化,确保内容更新时重新判断是否超行
  • 用Set存储展开行ID,避免重复状态,提升性能
  • 展开后将WebkitLineClamp设为unset,让内容完全显示

内容的提问来源于stack exchange,提问作者Jacki

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 12:35:24