请问,是否可以设定Table的宽度,或者不让其超过父容器呢?

我写了一个可编辑Cell的List:

import React, { useState } from 'react';
import type { TableProps } from 'antd';
import { Button, Form, Input, InputNumber, Popconfirm, Space, Table, Typography } from 'antd';

interface EditableCellProps extends React.HTMLAttributes<HTMLElement> {
  editing: boolean;
  dataIndex: string;
  title: any;
  inputType: 'number' | 'text';
  record: any;
  index: number;
}

const EditableCell: React.FC<React.PropsWithChildren<EditableCellProps>> = ({
  editing,
  dataIndex,
  title,
  inputType,
  record,
  index,
  children,
  ...restProps
}) => {
  const inputNode = inputType === 'number' ? <InputNumber /> : <Input />;

  return (
    <td {...restProps}>
      {editing ? (
        <Form.Item
          name={dataIndex}
          style={{ margin: 0 }}
          rules={[
            {
              required: true,
              message: `Please Input ${title}!`,
            },
          ]}
        >
          {inputNode}
        </Form.Item>
      ) : (
        children
      )}
    </td>
  );
};

// 使用泛型 T 来表示数据类型
interface IndexProps<T> {
  itemType: {
    [K in keyof T]: string;
  };
  initialData: T[];
  onEdit: (record: T) => void;
  onDelete: (record: T) => void;
}

const Index = <T extends { key: React.Key }>({ itemType, initialData, onEdit, onDelete }: IndexProps<T>) => {
  const [form] = Form.useForm();
  const [data, setData] = useState(initialData);
  const [editingKey, setEditingKey] = useState<React.Key>('');

  const isEditing = (record: T) => record.key === editingKey;

  const handleEdit = (record: T) => {
    form.setFieldsValue({ ...record });
    setEditingKey(record.key);
  };

  const handleCancel = () => {
    setEditingKey('');
  };

  const handleSave = async (key: React.Key) => {
    try {
      const row = (await form.validateFields()) as T;

      const newData = [...data];
      const index = newData.findIndex((item) => key === item.key);
      if (index > -1) {
        const item = newData[index];
        newData.splice(index, 1, {
          ...item,
          ...row,
        });
        onEdit(row);
        setData(newData);
        setEditingKey('');
      } else {
        newData.push(row);
        onEdit(row);
        setData(newData);
        setEditingKey('');
      }
    } catch (errInfo) {
      console.log('Validate Failed:', errInfo);
    }
  };

  const handleDelete = (record: T) => {
    onDelete(record);
  };

  const generateColumns = () => {
    const columns = [];
    for (const key in itemType) {
      if (key === 'key') continue;
      columns.push({
        title: key,
        dataIndex: key,
        width: key === 'name' ? '25%' : '100px',
        editable: true,
      });
    }
    columns.push({
      title: 'operation',
      dataIndex: 'operation',
      render: (_: any, record: T) => {
        const editable = isEditing(record);
        return editable ? (
          <span>
            <Typography.Link onClick={() => handleSave(record.key)} style={{ marginInlineEnd: 8 }}>
              保存
            </Typography.Link>
            <Popconfirm title="确定要取消吗?" onConfirm={handleCancel}>
              <a>取消</a>
            </Popconfirm>
          </span>
        ) : (
          <>
            <Space>
              <Button
                size='small'
                variant="filled"
                onClick={() => handleEdit(record)}
              >
                编辑
              </Button>
              <Popconfirm title="确定要删除吗?" onConfirm={() => handleDelete(record)}>
                <Button
                  size='small'
                  color="danger"
                  variant="filled">
                  删除
                </Button>
              </Popconfirm>
            </Space>
          </>
        );
      },
    });
    return columns;
  };

  const columns = generateColumns();

  const mergedColumns: TableProps<T>['columns'] = columns.map((col) => {
    if (!col.editable) {
      return col;
    }
    return {
      ...col,
      onCell: (record: T) => ({
        record,
        inputType: col.dataIndex === 'age' ? 'number' : 'text',
        dataIndex: col.dataIndex,
        title: col.title,
        editing: isEditing(record),
      }),
    };
  });

  return (
    <Form form={form} component={false}>
      <Table<T>
        components={{
          body: { cell: EditableCell },
        }}
        bordered
        dataSource={data}
        columns={mergedColumns}
        rowClassName="editable-row"
        pagination={false}
      />
    </Form>
  );
};

export default Index;

使用方式:

const funcEditListType = {
  key: '',
  funcname: '',
  funpath: ''
};
const funcEditListInitialData: typeof funcEditListType[] = [
  {
    key: '1',
    funcname: `Edward 1`,
    funpath: '/path/to/1234567890--9876543456'
  }
];

const handleFuncEdit = (record: typeof funcEditListType) => {
  console.log('编辑操作回调,记录:', record);
};

const handleFuncDelete = (record: typeof funcEditListType) => {
  console.log('删除操作回调,记录:', record);
};
...
 <EditableList itemType={funcEditListType} initialData={funcEditListInitialData} onEdit={handleFuncEdit} onDelete={handleFuncDelete} />

现在的问题是,比如:内容过长会直接冲出父容器:
image.png

请问,是否可以设定Table的宽度,或者不让其超过父容器呢?

阅读 580
avatarAI BotBETA

可以通过以下两种方式解决表格超出父容器的问题:

  1. 设置表格固定布局(推荐):

    <Table
      // 添加这两个属性
      style={{ width: '100%' }}
      tableLayout="fixed"
      // 其他原有属性...
    />
  2. 设置横向滚动条

    <Table
      scroll={{ x: 'max-content' }}
      // 其他原有属性...
    />

需要同时调整列宽设置

// 修改生成列宽的逻辑
columns.push({
  title: key,
  dataIndex: key,
  width: '20%', // 改用百分比分配
  // 或固定宽度(需要计算总宽度)
  // width: 200,
  ellipsis: true, // 添加文本溢出省略
  editable: true,
});

补充说明

  1. tableLayout="fixed" 会启用固定表格布局算法,列宽由设置的宽度决定
  2. 设置百分比宽度时需确保所有列的百分比总和不超过100%
  3. 添加 ellipsis: true 可以使过长文本显示为省略号
  4. 如果使用滚动方案,建议给表格容器设置最大宽度:

    .ant-table-wrapper {
      max-width: 100%;
      overflow-x: auto;
    }

修改后的列生成函数示例

const generateColumns = () => {
  const keys = Object.keys(itemType).filter(k => k !== 'key');
  const baseWidth = `${Math.floor(100 / keys.length)}%`;

  const columns = keys.map(key => ({
    title: key,
    dataIndex: key,
    width: baseWidth,
    ellipsis: true,
    editable: true,
  }));

  // 操作列保持固定宽度
  columns.push({
    title: 'operation',
    dataIndex: 'operation',
    width: 150, // 固定操作列宽度
    fixed: 'right' as const // 固定到右侧(需要设置scroll.x)
  });
  
  return columns;
};
2 个回答

加scroll和width

// ...  ...

return (
  <Form form={form} component={false}>
    <Table<T>
      components={{
        body: { cell: EditableCell },
      }}
      bordered
      dataSource={data}
      columns={mergedColumns}
      rowClassName="editable-row"
      pagination={false}
      scroll={{ x: '100%' }}
      style={{ width: '100%' }}
    />
  </Form>
);

// ......

如果只是解决当前问题,可以看到是这个单元格的路径超长了,截断超长字符即可:

const columns = [
 {
    title: 'Long Column Long Column Long Column',
    ellipsis: true,
  },
...
]

如果要整体的方案,可以参考官方的做法,添加滚动条,把右侧的操作列固定。

const columns = [
  ...,
  {
    title: 'operation',
    fixed: 'right',
  },
]

const App = () => {
  return (
    <Table
      ...
      columns={columns}
      scroll={{ x: 'max-content' }}
    />
  );
};
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题