Table 表格 #
概述 #
Table 表格是展示数据的核心组件,支持分页、排序、筛选、选择等功能,是企业级应用中最常用的组件之一。
基础用法 #
基本表格 #
tsx
import { Table } from 'antd';
const columns = [
{ title: '姓名', dataIndex: 'name', key: 'name' },
{ title: '年龄', dataIndex: 'age', key: 'age' },
{ title: '地址', dataIndex: 'address', key: 'address' },
];
const data = [
{ key: '1', name: '张三', age: 32, address: '北京市朝阳区' },
{ key: '2', name: '李四', age: 42, address: '上海市浦东新区' },
{ key: '3', name: '王五', age: 28, address: '广州市天河区' },
];
<Table columns={columns} dataSource={data} />
带边框表格 #
tsx
import { Table } from 'antd';
<Table columns={columns} dataSource={data} bordered />
加载状态 #
tsx
import { Table } from 'antd';
<Table columns={columns} dataSource={data} loading />
可展开表格 #
tsx
import { Table } from 'antd';
<Table
columns={columns}
dataSource={data}
expandable={{
expandedRowRender: (record) => (
<p style={{ margin: 0 }}>{record.description}</p>
),
rowExpandable: (record) => record.name !== 'Not Expandable',
}}
/>
分页 #
基本分页 #
tsx
import { Table } from 'antd';
<Table
columns={columns}
dataSource={data}
pagination={{ pageSize: 10 }}
/>
分页配置 #
tsx
import { Table } from 'antd';
<Table
columns={columns}
dataSource={data}
pagination={{
current: 1,
pageSize: 10,
total: 100,
showSizeChanger: true,
showQuickJumper: true,
showTotal: (total) => `共 ${total} 条`,
}}
/>
服务端分页 #
tsx
import { Table } from 'antd';
import { useState, useEffect } from 'react';
const App = () => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
const [pagination, setPagination] = useState({
current: 1,
pageSize: 10,
total: 0,
});
const fetchData = async (params = {}) => {
setLoading(true);
const result = await fetch(`/api/users?${new URLSearchParams(params)}`);
setData(result.data);
setPagination({
...pagination,
total: result.total,
});
setLoading(false);
};
const handleTableChange = (pagination) => {
fetchData({
page: pagination.current,
pageSize: pagination.pageSize,
});
};
useEffect(() => {
fetchData();
}, []);
return (
<Table
columns={columns}
dataSource={data}
loading={loading}
pagination={pagination}
onChange={handleTableChange}
/>
);
};
排序 #
本地排序 #
tsx
import { Table } from 'antd';
const columns = [
{ title: '姓名', dataIndex: 'name', key: 'name' },
{
title: '年龄',
dataIndex: 'age',
key: 'age',
sorter: (a, b) => a.age - b.age,
},
{
title: '地址',
dataIndex: 'address',
key: 'address',
sorter: (a, b) => a.address.localeCompare(b.address),
},
];
<Table columns={columns} dataSource={data} />
远程排序 #
tsx
import { Table } from 'antd';
const columns = [
{ title: '姓名', dataIndex: 'name', key: 'name' },
{
title: '年龄',
dataIndex: 'age',
key: 'age',
sorter: true,
},
];
const handleTableChange = (pagination, filters, sorter) => {
fetchData({
sortField: sorter.field,
sortOrder: sorter.order,
});
};
<Table
columns={columns}
dataSource={data}
onChange={handleTableChange}
/>
筛选 #
本地筛选 #
tsx
import { Table } from 'antd';
const columns = [
{
title: '姓名',
dataIndex: 'name',
key: 'name',
filters: [
{ text: '张三', value: '张三' },
{ text: '李四', value: '李四' },
],
onFilter: (value, record) => record.name.includes(value),
},
{
title: '年龄',
dataIndex: 'age',
key: 'age',
sorter: (a, b) => a.age - b.age,
},
];
<Table columns={columns} dataSource={data} />
远程筛选 #
tsx
import { Table } from 'antd';
const columns = [
{
title: '姓名',
dataIndex: 'name',
key: 'name',
filters: [
{ text: '张三', value: '张三' },
{ text: '李四', value: '李四' },
],
},
];
const handleTableChange = (pagination, filters) => {
fetchData({
name: filters.name,
});
};
<Table
columns={columns}
dataSource={data}
onChange={handleTableChange}
/>
选择 #
复选框选择 #
tsx
import { Table } from 'antd';
import { useState } from 'react';
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const rowSelection = {
selectedRowKeys,
onChange: (keys) => setSelectedRowKeys(keys),
};
<Table
rowSelection={rowSelection}
columns={columns}
dataSource={data}
/>
单选 #
tsx
import { Table } from 'antd';
const rowSelection = {
type: 'radio',
onChange: (selectedRowKeys, selectedRows) => {
console.log(selectedRows);
},
};
<Table
rowSelection={rowSelection}
columns={columns}
dataSource={data}
/>
自定义选择 #
tsx
import { Table } from 'antd';
const rowSelection = {
selections: [
Table.SELECTION_ALL,
Table.SELECTION_INVERT,
Table.SELECTION_NONE,
{
key: 'odd',
text: '选择奇数行',
onSelect: (changeableRowKeys) => {
let newSelectedRowKeys = [];
newSelectedRowKeys = changeableRowKeys.filter((_, index) => {
if (index % 2 !== 0) {
return false;
}
return true;
});
setSelectedRowKeys(newSelectedRowKeys);
},
},
],
};
<Table
rowSelection={rowSelection}
columns={columns}
dataSource={data}
/>
固定列 #
左侧固定 #
tsx
import { Table } from 'antd';
const columns = [
{
title: '姓名',
dataIndex: 'name',
key: 'name',
fixed: 'left',
width: 100,
},
{ title: '年龄', dataIndex: 'age', key: 'age', width: 100 },
{ title: '地址', dataIndex: 'address', key: 'address' },
];
<Table columns={columns} dataSource={data} scroll={{ x: 1300 }} />
右侧固定 #
tsx
import { Table } from 'antd';
const columns = [
{ title: '姓名', dataIndex: 'name', key: 'name' },
{ title: '年龄', dataIndex: 'age', key: 'age' },
{
title: '操作',
key: 'action',
fixed: 'right',
width: 100,
render: () => <a>删除</a>,
},
];
<Table columns={columns} dataSource={data} scroll={{ x: 1300 }} />
固定表头 #
tsx
import { Table } from 'antd';
<Table
columns={columns}
dataSource={data}
scroll={{ y: 400 }}
/>
可编辑表格 #
tsx
import { Table, Input, Form } from 'antd';
import { useState } from 'react';
const EditableCell = ({
editing,
dataIndex,
title,
record,
children,
...restProps
}) => {
return (
<td {...restProps}>
{editing ? (
<Form.Item
name={dataIndex}
style={{ margin: 0 }}
rules={[{ required: true, message: `请输入${title}` }]}
>
<Input />
</Form.Item>
) : (
children
)}
</td>
);
};
const App = () => {
const [form] = Form.useForm();
const [editingKey, setEditingKey] = useState('');
const isEditing = (record) => record.key === editingKey;
const edit = (record) => {
form.setFieldsValue({ ...record });
setEditingKey(record.key);
};
const columns = [
{ title: '姓名', dataIndex: 'name', key: 'name', editable: true },
{ title: '年龄', dataIndex: 'age', key: 'age', editable: true },
{
title: '操作',
dataIndex: 'operation',
render: (_, record) => {
const editable = isEditing(record);
return editable ? (
<span>
<a onClick={() => save(record.key)}>保存</a>
<a onClick={() => cancel()}>取消</a>
</span>
) : (
<a disabled={editingKey !== ''} onClick={() => edit(record)}>
编辑
</a>
);
},
},
];
const mergedColumns = columns.map((col) => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: (record) => ({
record,
dataIndex: col.dataIndex,
title: col.title,
editing: isEditing(record),
}),
};
});
return (
<Form form={form} component={false}>
<Table
components={{
body: {
cell: EditableCell,
},
}}
columns={mergedColumns}
dataSource={data}
/>
</Form>
);
};
API #
Table #
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| bordered | 是否显示边框 | boolean | false |
| columns | 表格列配置 | ColumnType[] | - |
| dataSource | 数据源 | object[] | - |
| expandable | 展开配置 | expandable | - |
| footer | 表格尾部 | () => ReactNode | - |
| loading | 加载状态 | boolean | SpinProps | false |
| locale | 国际化配置 | object | - |
| pagination | 分页配置 | PaginationConfig | false | - |
| rowClassName | 行类名 | (record, index) => string | - |
| rowKey | 行 key | string | (record) => string | key |
| rowSelection | 选择配置 | RowSelection | - |
| scroll | 滚动配置 | - | |
| showHeader | 是否显示表头 | boolean | true |
| showSorterTooltip | 排序提示 | boolean | true |
| size | 表格大小 | default | middle | small |
default |
| sortDirections | 排序方向 | (ascend | descend)[] |
- |
| sticky | 粘性头部 | boolean | Sticky | - |
| summary | 总结栏 | (currentData) => ReactNode | - |
| tableLayout | 表格布局 | auto | fixed |
- |
| title | 表格标题 | () => ReactNode | - |
| onChange | 分页排序筛选变化回调 | (pagination, filters, sorter, extra) => void | - |
| onHeaderRow | 表头行属性 | (columns, index) => object | - |
| onRow | 行属性 | (record, index) => object | - |
Column #
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| align | 对齐方式 | left | right | center |
left |
| className | 列类名 | string | - |
| colSpan | 合并列 | number | - |
| dataIndex | 数据字段名 | string | - |
| ellipsis | 超出省略 | boolean | | false |
| filters | 筛选菜单 | { text, value }[] | - |
| filterDropdown | 自定义筛选 | ReactNode | - |
| filterDropdownProps | 筛选菜单属性 | object | - |
| filterMultiple | 是否多选 | boolean | true |
| filterSearch | 筛选搜索 | boolean | function | false |
| fixed | 固定列 | left | right |
- |
| key | React key | string | - |
| render | 渲染函数 | (text, record, index) => ReactNode | - |
| responsive | 响应式 | Breakpoint[] | - |
| rowScope | 行作用域 | row | col |
- |
| shouldCellUpdate | 单元格更新 | (record, prevRecord) => boolean | - |
| showSorterTooltip | 排序提示 | boolean | TooltipProps | - |
| sortDirections | 排序方向 | (ascend | descend)[] |
- |
| sorter | 排序函数 | boolean | function | - |
| sortOrder | 排序状态 | ascend | descend |
- |
| title | 列标题 | ReactNode | - |
| width | 列宽度 | string | number | - |
| onCell | 单元格属性 | (record, index) => object | - |
| onFilter | 筛选函数 | (value, record) => boolean | - |
| onFilterDropdownOpenChange | 筛选菜单展开回调 | (visible) => void | - |
| onHeaderCell | 表头单元格属性 | (column) => object | - |
最佳实践 #
1. 性能优化 #
tsx
import { Table } from 'antd';
import { useMemo } from 'react';
const columns = useMemo(() => [
{ title: '姓名', dataIndex: 'name' },
{ title: '年龄', dataIndex: 'age' },
], []);
<Table columns={columns} dataSource={data} />
2. 虚拟滚动 #
tsx
import { Table } from 'antd';
<Table
virtual
scroll={{ x: 2000, y: 500 }}
columns={columns}
dataSource={largeData}
/>
3. 处理大数据 #
tsx
import { Table } from 'antd';
<Table
columns={columns}
dataSource={data}
pagination={{
pageSize: 20,
showSizeChanger: true,
}}
scroll={{ y: 500 }}
/>
下一步 #
接下来学习 List 列表 组件!
最后更新:2026-03-28