Table表格

展示行列数据。

设计师专属

安装 Kitchen Sketch 插件 💎,两步就可以自动生成 Ant Design 表格组件。

何时使用

  • 当有大量结构化的数据需要展现时;

  • 当需要对数据进行排序、搜索、分页、自定义操作等复杂行为时。

如何使用

指定表格的数据源 dataSource 为一个数组。

  1. const dataSource = [
  2. {
  3. key: '1',
  4. name: '胡彦斌',
  5. age: 32,
  6. address: '西湖区湖底公园1号',
  7. },
  8. {
  9. key: '2',
  10. name: '胡彦祖',
  11. age: 42,
  12. address: '西湖区湖底公园1号',
  13. },
  14. ];
  15. const columns = [
  16. {
  17. title: '姓名',
  18. dataIndex: 'name',
  19. key: 'name',
  20. },
  21. {
  22. title: '年龄',
  23. dataIndex: 'age',
  24. key: 'age',
  25. },
  26. {
  27. title: '住址',
  28. dataIndex: 'address',
  29. key: 'address',
  30. },
  31. ];
  32. <Table dataSource={dataSource} columns={columns} />;

代码演示

Table表格 - 图1

基本用法

简单的表格,最后一列是各种操作。

  1. import { Table, Divider, Tag } from 'antd';
  2. const columns = [
  3. {
  4. title: 'Name',
  5. dataIndex: 'name',
  6. key: 'name',
  7. render: text => <a>{text}</a>,
  8. },
  9. {
  10. title: 'Age',
  11. dataIndex: 'age',
  12. key: 'age',
  13. },
  14. {
  15. title: 'Address',
  16. dataIndex: 'address',
  17. key: 'address',
  18. },
  19. {
  20. title: 'Tags',
  21. key: 'tags',
  22. dataIndex: 'tags',
  23. render: tags => (
  24. <span>
  25. {tags.map(tag => {
  26. let color = tag.length > 5 ? 'geekblue' : 'green';
  27. if (tag === 'loser') {
  28. color = 'volcano';
  29. }
  30. return (
  31. <Tag color={color} key={tag}>
  32. {tag.toUpperCase()}
  33. </Tag>
  34. );
  35. })}
  36. </span>
  37. ),
  38. },
  39. {
  40. title: 'Action',
  41. key: 'action',
  42. render: (text, record) => (
  43. <span>
  44. <a>Invite {record.name}</a>
  45. <Divider type="vertical" />
  46. <a>Delete</a>
  47. </span>
  48. ),
  49. },
  50. ];
  51. const data = [
  52. {
  53. key: '1',
  54. name: 'John Brown',
  55. age: 32,
  56. address: 'New York No. 1 Lake Park',
  57. tags: ['nice', 'developer'],
  58. },
  59. {
  60. key: '2',
  61. name: 'Jim Green',
  62. age: 42,
  63. address: 'London No. 1 Lake Park',
  64. tags: ['loser'],
  65. },
  66. {
  67. key: '3',
  68. name: 'Joe Black',
  69. age: 32,
  70. address: 'Sidney No. 1 Lake Park',
  71. tags: ['cool', 'teacher'],
  72. },
  73. ];
  74. ReactDOM.render(<Table columns={columns} dataSource={data} />, mountNode);

Table表格 - 图2

JSX 风格的 API

使用 JSX 风格的 API(2.5.0 以后引入)

这个只是一个描述 columns 的语法糖,所以你不能用其他组件去包裹 ColumnColumnGroup

  1. import { Table, Divider, Tag } from 'antd';
  2. const { Column, ColumnGroup } = Table;
  3. const data = [
  4. {
  5. key: '1',
  6. firstName: 'John',
  7. lastName: 'Brown',
  8. age: 32,
  9. address: 'New York No. 1 Lake Park',
  10. tags: ['nice', 'developer'],
  11. },
  12. {
  13. key: '2',
  14. firstName: 'Jim',
  15. lastName: 'Green',
  16. age: 42,
  17. address: 'London No. 1 Lake Park',
  18. tags: ['loser'],
  19. },
  20. {
  21. key: '3',
  22. firstName: 'Joe',
  23. lastName: 'Black',
  24. age: 32,
  25. address: 'Sidney No. 1 Lake Park',
  26. tags: ['cool', 'teacher'],
  27. },
  28. ];
  29. ReactDOM.render(
  30. <Table dataSource={data}>
  31. <ColumnGroup title="Name">
  32. <Column title="First Name" dataIndex="firstName" key="firstName" />
  33. <Column title="Last Name" dataIndex="lastName" key="lastName" />
  34. </ColumnGroup>
  35. <Column title="Age" dataIndex="age" key="age" />
  36. <Column title="Address" dataIndex="address" key="address" />
  37. <Column
  38. title="Tags"
  39. dataIndex="tags"
  40. key="tags"
  41. render={tags => (
  42. <span>
  43. {tags.map(tag => (
  44. <Tag color="blue" key={tag}>
  45. {tag}
  46. </Tag>
  47. ))}
  48. </span>
  49. )}
  50. />
  51. <Column
  52. title="Action"
  53. key="action"
  54. render={(text, record) => (
  55. <span>
  56. <a>Invite {record.lastName}</a>
  57. <Divider type="vertical" />
  58. <a>Delete</a>
  59. </span>
  60. )}
  61. />
  62. </Table>,
  63. mountNode,
  64. );

Table表格 - 图3

可选择

第一列是联动的选择框。

默认点击 checkbox 触发选择行为,需要点击行触发可以参考例子:https://codesandbox.io/s/000vqw38rl

  1. import { Table } from 'antd';
  2. const columns = [
  3. {
  4. title: 'Name',
  5. dataIndex: 'name',
  6. render: text => <a>{text}</a>,
  7. },
  8. {
  9. title: 'Age',
  10. dataIndex: 'age',
  11. },
  12. {
  13. title: 'Address',
  14. dataIndex: 'address',
  15. },
  16. ];
  17. const data = [
  18. {
  19. key: '1',
  20. name: 'John Brown',
  21. age: 32,
  22. address: 'New York No. 1 Lake Park',
  23. },
  24. {
  25. key: '2',
  26. name: 'Jim Green',
  27. age: 42,
  28. address: 'London No. 1 Lake Park',
  29. },
  30. {
  31. key: '3',
  32. name: 'Joe Black',
  33. age: 32,
  34. address: 'Sidney No. 1 Lake Park',
  35. },
  36. {
  37. key: '4',
  38. name: 'Disabled User',
  39. age: 99,
  40. address: 'Sidney No. 1 Lake Park',
  41. },
  42. ];
  43. // rowSelection object indicates the need for row selection
  44. const rowSelection = {
  45. onChange: (selectedRowKeys, selectedRows) => {
  46. console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
  47. },
  48. getCheckboxProps: record => ({
  49. disabled: record.name === 'Disabled User', // Column configuration not to be checked
  50. name: record.name,
  51. }),
  52. };
  53. ReactDOM.render(
  54. <Table rowSelection={rowSelection} columns={columns} dataSource={data} />,
  55. mountNode,
  56. );

Table表格 - 图4

选择和操作

选择后进行操作,完成后清空选择,通过 rowSelection.selectedRowKeys 来控制选中项。

  1. import { Table, Button } from 'antd';
  2. const columns = [
  3. {
  4. title: 'Name',
  5. dataIndex: 'name',
  6. },
  7. {
  8. title: 'Age',
  9. dataIndex: 'age',
  10. },
  11. {
  12. title: 'Address',
  13. dataIndex: 'address',
  14. },
  15. ];
  16. const data = [];
  17. for (let i = 0; i < 46; i++) {
  18. data.push({
  19. key: i,
  20. name: `Edward King ${i}`,
  21. age: 32,
  22. address: `London, Park Lane no. ${i}`,
  23. });
  24. }
  25. class App extends React.Component {
  26. state = {
  27. selectedRowKeys: [], // Check here to configure the default column
  28. loading: false,
  29. };
  30. start = () => {
  31. this.setState({ loading: true });
  32. // ajax request after empty completing
  33. setTimeout(() => {
  34. this.setState({
  35. selectedRowKeys: [],
  36. loading: false,
  37. });
  38. }, 1000);
  39. };
  40. onSelectChange = selectedRowKeys => {
  41. console.log('selectedRowKeys changed: ', selectedRowKeys);
  42. this.setState({ selectedRowKeys });
  43. };
  44. render() {
  45. const { loading, selectedRowKeys } = this.state;
  46. const rowSelection = {
  47. selectedRowKeys,
  48. onChange: this.onSelectChange,
  49. };
  50. const hasSelected = selectedRowKeys.length > 0;
  51. return (
  52. <div>
  53. <div style={{ marginBottom: 16 }}>
  54. <Button type="primary" onClick={this.start} disabled={!hasSelected} loading={loading}>
  55. Reload
  56. </Button>
  57. <span style={{ marginLeft: 8 }}>
  58. {hasSelected ? `Selected ${selectedRowKeys.length} items` : ''}
  59. </span>
  60. </div>
  61. <Table rowSelection={rowSelection} columns={columns} dataSource={data} />
  62. </div>
  63. );
  64. }
  65. }
  66. ReactDOM.render(<App />, mountNode);

Table表格 - 图5

自定义选择项

通过 rowSelection.selections 自定义选择项,默认不显示下拉选项,设为 true 时显示默认选择项。

  1. import { Table } from 'antd';
  2. const columns = [
  3. {
  4. title: 'Name',
  5. dataIndex: 'name',
  6. },
  7. {
  8. title: 'Age',
  9. dataIndex: 'age',
  10. },
  11. {
  12. title: 'Address',
  13. dataIndex: 'address',
  14. },
  15. ];
  16. const data = [];
  17. for (let i = 0; i < 46; i++) {
  18. data.push({
  19. key: i,
  20. name: `Edward King ${i}`,
  21. age: 32,
  22. address: `London, Park Lane no. ${i}`,
  23. });
  24. }
  25. class App extends React.Component {
  26. state = {
  27. selectedRowKeys: [], // Check here to configure the default column
  28. };
  29. onSelectChange = selectedRowKeys => {
  30. console.log('selectedRowKeys changed: ', selectedRowKeys);
  31. this.setState({ selectedRowKeys });
  32. };
  33. render() {
  34. const { selectedRowKeys } = this.state;
  35. const rowSelection = {
  36. selectedRowKeys,
  37. onChange: this.onSelectChange,
  38. hideDefaultSelections: true,
  39. selections: [
  40. {
  41. key: 'all-data',
  42. text: 'Select All Data',
  43. onSelect: () => {
  44. this.setState({
  45. selectedRowKeys: [...Array(46).keys()], // 0...45
  46. });
  47. },
  48. },
  49. {
  50. key: 'odd',
  51. text: 'Select Odd Row',
  52. onSelect: changableRowKeys => {
  53. let newSelectedRowKeys = [];
  54. newSelectedRowKeys = changableRowKeys.filter((key, index) => {
  55. if (index % 2 !== 0) {
  56. return false;
  57. }
  58. return true;
  59. });
  60. this.setState({ selectedRowKeys: newSelectedRowKeys });
  61. },
  62. },
  63. {
  64. key: 'even',
  65. text: 'Select Even Row',
  66. onSelect: changableRowKeys => {
  67. let newSelectedRowKeys = [];
  68. newSelectedRowKeys = changableRowKeys.filter((key, index) => {
  69. if (index % 2 !== 0) {
  70. return true;
  71. }
  72. return false;
  73. });
  74. this.setState({ selectedRowKeys: newSelectedRowKeys });
  75. },
  76. },
  77. ],
  78. };
  79. return <Table rowSelection={rowSelection} columns={columns} dataSource={data} />;
  80. }
  81. }
  82. ReactDOM.render(<App />, mountNode);

Table表格 - 图6

筛选和排序

对某一列数据进行筛选,使用列的 filters 属性来指定需要筛选菜单的列,onFilter 用于筛选当前数据,filterMultiple 用于指定多选和单选。

对某一列数据进行排序,通过指定列的 sorter 函数即可启动排序按钮。sorter: function(rowA, rowB) { … }, rowA、rowB 为比较的两个行数据。

sortDirections: ['ascend' | 'descend']改变每列可用的排序方式,切换排序时按数组内容依次切换,设置在 table props 上时对所有列生效。

使用 defaultSortOrder 属性,设置列的默认排序顺序。

  1. import { Table } from 'antd';
  2. const columns = [
  3. {
  4. title: 'Name',
  5. dataIndex: 'name',
  6. filters: [
  7. {
  8. text: 'Joe',
  9. value: 'Joe',
  10. },
  11. {
  12. text: 'Jim',
  13. value: 'Jim',
  14. },
  15. {
  16. text: 'Submenu',
  17. value: 'Submenu',
  18. children: [
  19. {
  20. text: 'Green',
  21. value: 'Green',
  22. },
  23. {
  24. text: 'Black',
  25. value: 'Black',
  26. },
  27. ],
  28. },
  29. ],
  30. // specify the condition of filtering result
  31. // here is that finding the name started with `value`
  32. onFilter: (value, record) => record.name.indexOf(value) === 0,
  33. sorter: (a, b) => a.name.length - b.name.length,
  34. sortDirections: ['descend'],
  35. },
  36. {
  37. title: 'Age',
  38. dataIndex: 'age',
  39. defaultSortOrder: 'descend',
  40. sorter: (a, b) => a.age - b.age,
  41. },
  42. {
  43. title: 'Address',
  44. dataIndex: 'address',
  45. filters: [
  46. {
  47. text: 'London',
  48. value: 'London',
  49. },
  50. {
  51. text: 'New York',
  52. value: 'New York',
  53. },
  54. ],
  55. filterMultiple: false,
  56. onFilter: (value, record) => record.address.indexOf(value) === 0,
  57. sorter: (a, b) => a.address.length - b.address.length,
  58. sortDirections: ['descend', 'ascend'],
  59. },
  60. ];
  61. const data = [
  62. {
  63. key: '1',
  64. name: 'John Brown',
  65. age: 32,
  66. address: 'New York No. 1 Lake Park',
  67. },
  68. {
  69. key: '2',
  70. name: 'Jim Green',
  71. age: 42,
  72. address: 'London No. 1 Lake Park',
  73. },
  74. {
  75. key: '3',
  76. name: 'Joe Black',
  77. age: 32,
  78. address: 'Sidney No. 1 Lake Park',
  79. },
  80. {
  81. key: '4',
  82. name: 'Jim Red',
  83. age: 32,
  84. address: 'London No. 2 Lake Park',
  85. },
  86. ];
  87. function onChange(pagination, filters, sorter, extra) {
  88. console.log('params', pagination, filters, sorter, extra);
  89. }
  90. ReactDOM.render(<Table columns={columns} dataSource={data} onChange={onChange} />, mountNode);

Table表格 - 图7

可控的筛选和排序

使用受控属性对筛选和排序状态进行控制。

  1. columns 中定义了 filteredValue 和 sortOrder 属性即视为受控模式。

  2. 只支持同时对一列进行排序,请保证只有一列的 sortOrder 属性是生效的。

  3. 务必指定 column.key

  1. import { Table, Button } from 'antd';
  2. const data = [
  3. {
  4. key: '1',
  5. name: 'John Brown',
  6. age: 32,
  7. address: 'New York No. 1 Lake Park',
  8. },
  9. {
  10. key: '2',
  11. name: 'Jim Green',
  12. age: 42,
  13. address: 'London No. 1 Lake Park',
  14. },
  15. {
  16. key: '3',
  17. name: 'Joe Black',
  18. age: 32,
  19. address: 'Sidney No. 1 Lake Park',
  20. },
  21. {
  22. key: '4',
  23. name: 'Jim Red',
  24. age: 32,
  25. address: 'London No. 2 Lake Park',
  26. },
  27. ];
  28. class App extends React.Component {
  29. state = {
  30. filteredInfo: null,
  31. sortedInfo: null,
  32. };
  33. handleChange = (pagination, filters, sorter) => {
  34. console.log('Various parameters', pagination, filters, sorter);
  35. this.setState({
  36. filteredInfo: filters,
  37. sortedInfo: sorter,
  38. });
  39. };
  40. clearFilters = () => {
  41. this.setState({ filteredInfo: null });
  42. };
  43. clearAll = () => {
  44. this.setState({
  45. filteredInfo: null,
  46. sortedInfo: null,
  47. });
  48. };
  49. setAgeSort = () => {
  50. this.setState({
  51. sortedInfo: {
  52. order: 'descend',
  53. columnKey: 'age',
  54. },
  55. });
  56. };
  57. render() {
  58. let { sortedInfo, filteredInfo } = this.state;
  59. sortedInfo = sortedInfo || {};
  60. filteredInfo = filteredInfo || {};
  61. const columns = [
  62. {
  63. title: 'Name',
  64. dataIndex: 'name',
  65. key: 'name',
  66. filters: [{ text: 'Joe', value: 'Joe' }, { text: 'Jim', value: 'Jim' }],
  67. filteredValue: filteredInfo.name || null,
  68. onFilter: (value, record) => record.name.includes(value),
  69. sorter: (a, b) => a.name.length - b.name.length,
  70. sortOrder: sortedInfo.columnKey === 'name' && sortedInfo.order,
  71. ellipsis: true,
  72. },
  73. {
  74. title: 'Age',
  75. dataIndex: 'age',
  76. key: 'age',
  77. sorter: (a, b) => a.age - b.age,
  78. sortOrder: sortedInfo.columnKey === 'age' && sortedInfo.order,
  79. ellipsis: true,
  80. },
  81. {
  82. title: 'Address',
  83. dataIndex: 'address',
  84. key: 'address',
  85. filters: [{ text: 'London', value: 'London' }, { text: 'New York', value: 'New York' }],
  86. filteredValue: filteredInfo.address || null,
  87. onFilter: (value, record) => record.address.includes(value),
  88. sorter: (a, b) => a.address.length - b.address.length,
  89. sortOrder: sortedInfo.columnKey === 'address' && sortedInfo.order,
  90. ellipsis: true,
  91. },
  92. ];
  93. return (
  94. <div>
  95. <div className="table-operations">
  96. <Button onClick={this.setAgeSort}>Sort age</Button>
  97. <Button onClick={this.clearFilters}>Clear filters</Button>
  98. <Button onClick={this.clearAll}>Clear filters and sorters</Button>
  99. </div>
  100. <Table columns={columns} dataSource={data} onChange={this.handleChange} />
  101. </div>
  102. );
  103. }
  104. }
  105. ReactDOM.render(<App />, mountNode);
  1. .table-operations {
  2. margin-bottom: 16px;
  3. }
  4. .table-operations > button {
  5. margin-right: 8px;
  6. }

Table表格 - 图8

自定义筛选菜单

通过 filterDropdown 自定义的列筛选功能,并实现一个搜索列的示例。

  1. import { Table, Input, Button, Icon } from 'antd';
  2. import Highlighter from 'react-highlight-words';
  3. const data = [
  4. {
  5. key: '1',
  6. name: 'John Brown',
  7. age: 32,
  8. address: 'New York No. 1 Lake Park',
  9. },
  10. {
  11. key: '2',
  12. name: 'Joe Black',
  13. age: 42,
  14. address: 'London No. 1 Lake Park',
  15. },
  16. {
  17. key: '3',
  18. name: 'Jim Green',
  19. age: 32,
  20. address: 'Sidney No. 1 Lake Park',
  21. },
  22. {
  23. key: '4',
  24. name: 'Jim Red',
  25. age: 32,
  26. address: 'London No. 2 Lake Park',
  27. },
  28. ];
  29. class App extends React.Component {
  30. state = {
  31. searchText: '',
  32. searchedColumn: '',
  33. };
  34. getColumnSearchProps = dataIndex => ({
  35. filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => (
  36. <div style={{ padding: 8 }}>
  37. <Input
  38. ref={node => {
  39. this.searchInput = node;
  40. }}
  41. placeholder={`Search ${dataIndex}`}
  42. value={selectedKeys[0]}
  43. onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
  44. onPressEnter={() => this.handleSearch(selectedKeys, confirm, dataIndex)}
  45. style={{ width: 188, marginBottom: 8, display: 'block' }}
  46. />
  47. <Button
  48. type="primary"
  49. onClick={() => this.handleSearch(selectedKeys, confirm, dataIndex)}
  50. icon="search"
  51. size="small"
  52. style={{ width: 90, marginRight: 8 }}
  53. >
  54. Search
  55. </Button>
  56. <Button onClick={() => this.handleReset(clearFilters)} size="small" style={{ width: 90 }}>
  57. Reset
  58. </Button>
  59. </div>
  60. ),
  61. filterIcon: filtered => (
  62. <Icon type="search" style={{ color: filtered ? '#1890ff' : undefined }} />
  63. ),
  64. onFilter: (value, record) =>
  65. record[dataIndex]
  66. .toString()
  67. .toLowerCase()
  68. .includes(value.toLowerCase()),
  69. onFilterDropdownVisibleChange: visible => {
  70. if (visible) {
  71. setTimeout(() => this.searchInput.select());
  72. }
  73. },
  74. render: text => (
  75. (this.state.searchedColumn === dataIndex) ?
  76. <Highlighter
  77. highlightStyle={{ backgroundColor: '#ffc069', padding: 0 }}
  78. searchWords={[this.state.searchText]}
  79. autoEscape
  80. textToHighlight={text.toString()}
  81. />
  82. : text
  83. ),
  84. });
  85. handleSearch = (selectedKeys, confirm, dataIndex) => {
  86. confirm();
  87. this.setState({
  88. searchText: selectedKeys[0],
  89. searchedColumn: dataIndex,
  90. });
  91. };
  92. handleReset = clearFilters => {
  93. clearFilters();
  94. this.setState({ searchText: '' });
  95. };
  96. render() {
  97. const columns = [
  98. {
  99. title: 'Name',
  100. dataIndex: 'name',
  101. key: 'name',
  102. width: '30%',
  103. ...this.getColumnSearchProps('name'),
  104. },
  105. {
  106. title: 'Age',
  107. dataIndex: 'age',
  108. key: 'age',
  109. width: '20%',
  110. ...this.getColumnSearchProps('age'),
  111. },
  112. {
  113. title: 'Address',
  114. dataIndex: 'address',
  115. key: 'address',
  116. ...this.getColumnSearchProps('address'),
  117. },
  118. ];
  119. return <Table columns={columns} dataSource={data} />;
  120. }
  121. }
  122. ReactDOM.render(<App />, mountNode);

Table表格 - 图9

远程加载数据

这个例子通过简单的 ajax 读取方式,演示了如何从服务端读取并展现数据,具有筛选、排序等功能以及页面 loading 效果。开发者可以自行接入其他数据处理方式。

另外,本例也展示了筛选排序功能如何交给服务端实现,列不需要指定具体的 onFiltersorter 函数,而是在把筛选和排序的参数发到服务端来处理。

注意,此示例使用 模拟接口,展示数据可能不准确,请打开网络面板查看请求。

  1. import { Table } from 'antd';
  2. import reqwest from 'reqwest';
  3. const columns = [
  4. {
  5. title: 'Name',
  6. dataIndex: 'name',
  7. sorter: true,
  8. render: name => `${name.first} ${name.last}`,
  9. width: '20%',
  10. },
  11. {
  12. title: 'Gender',
  13. dataIndex: 'gender',
  14. filters: [{ text: 'Male', value: 'male' }, { text: 'Female', value: 'female' }],
  15. width: '20%',
  16. },
  17. {
  18. title: 'Email',
  19. dataIndex: 'email',
  20. },
  21. ];
  22. class App extends React.Component {
  23. state = {
  24. data: [],
  25. pagination: {},
  26. loading: false,
  27. };
  28. componentDidMount() {
  29. this.fetch();
  30. }
  31. handleTableChange = (pagination, filters, sorter) => {
  32. const pager = { ...this.state.pagination };
  33. pager.current = pagination.current;
  34. this.setState({
  35. pagination: pager,
  36. });
  37. this.fetch({
  38. results: pagination.pageSize,
  39. page: pagination.current,
  40. sortField: sorter.field,
  41. sortOrder: sorter.order,
  42. ...filters,
  43. });
  44. };
  45. fetch = (params = {}) => {
  46. console.log('params:', params);
  47. this.setState({ loading: true });
  48. reqwest({
  49. url: 'https://randomuser.me/api',
  50. method: 'get',
  51. data: {
  52. results: 10,
  53. ...params,
  54. },
  55. type: 'json',
  56. }).then(data => {
  57. const pagination = { ...this.state.pagination };
  58. // Read total count from server
  59. // pagination.total = data.totalCount;
  60. pagination.total = 200;
  61. this.setState({
  62. loading: false,
  63. data: data.results,
  64. pagination,
  65. });
  66. });
  67. };
  68. render() {
  69. return (
  70. <Table
  71. columns={columns}
  72. rowKey={record => record.login.uuid}
  73. dataSource={this.state.data}
  74. pagination={this.state.pagination}
  75. loading={this.state.loading}
  76. onChange={this.handleTableChange}
  77. />
  78. );
  79. }
  80. }
  81. ReactDOM.render(<App />, mountNode);

Table表格 - 图10

紧凑型

两种紧凑型的列表,小型列表只用于对话框内。

  1. import { Table } from 'antd';
  2. const columns = [
  3. {
  4. title: 'Name',
  5. dataIndex: 'name',
  6. },
  7. {
  8. title: 'Age',
  9. dataIndex: 'age',
  10. },
  11. {
  12. title: 'Address',
  13. dataIndex: 'address',
  14. },
  15. ];
  16. const data = [
  17. {
  18. key: '1',
  19. name: 'John Brown',
  20. age: 32,
  21. address: 'New York No. 1 Lake Park',
  22. },
  23. {
  24. key: '2',
  25. name: 'Jim Green',
  26. age: 42,
  27. address: 'London No. 1 Lake Park',
  28. },
  29. {
  30. key: '3',
  31. name: 'Joe Black',
  32. age: 32,
  33. address: 'Sidney No. 1 Lake Park',
  34. },
  35. ];
  36. ReactDOM.render(
  37. <div>
  38. <h4>Middle size table</h4>
  39. <Table columns={columns} dataSource={data} size="middle" />
  40. <h4>Small size table</h4>
  41. <Table columns={columns} dataSource={data} size="small" />
  42. </div>,
  43. mountNode,
  44. );

Table表格 - 图11

带边框

添加表格边框线,页头和页脚。

  1. import { Table } from 'antd';
  2. const columns = [
  3. {
  4. title: 'Name',
  5. dataIndex: 'name',
  6. render: text => <a>{text}</a>,
  7. },
  8. {
  9. title: 'Cash Assets',
  10. className: 'column-money',
  11. dataIndex: 'money',
  12. },
  13. {
  14. title: 'Address',
  15. dataIndex: 'address',
  16. },
  17. ];
  18. const data = [
  19. {
  20. key: '1',
  21. name: 'John Brown',
  22. money: '¥300,000.00',
  23. address: 'New York No. 1 Lake Park',
  24. },
  25. {
  26. key: '2',
  27. name: 'Jim Green',
  28. money: '¥1,256,000.00',
  29. address: 'London No. 1 Lake Park',
  30. },
  31. {
  32. key: '3',
  33. name: 'Joe Black',
  34. money: '¥120,000.00',
  35. address: 'Sidney No. 1 Lake Park',
  36. },
  37. ];
  38. ReactDOM.render(
  39. <Table
  40. columns={columns}
  41. dataSource={data}
  42. bordered
  43. title={() => 'Header'}
  44. footer={() => 'Footer'}
  45. />,
  46. mountNode,
  47. );
  1. th.column-money,
  2. td.column-money {
  3. text-align: right !important;
  4. }

Table表格 - 图12

可展开

当表格内容较多不能一次性完全展示时。

  1. import { Table } from 'antd';
  2. const columns = [
  3. { title: 'Name', dataIndex: 'name', key: 'name' },
  4. { title: 'Age', dataIndex: 'age', key: 'age' },
  5. { title: 'Address', dataIndex: 'address', key: 'address' },
  6. {
  7. title: 'Action',
  8. dataIndex: '',
  9. key: 'x',
  10. render: () => <a>Delete</a>,
  11. },
  12. ];
  13. const data = [
  14. {
  15. key: 1,
  16. name: 'John Brown',
  17. age: 32,
  18. address: 'New York No. 1 Lake Park',
  19. description: 'My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park.',
  20. },
  21. {
  22. key: 2,
  23. name: 'Jim Green',
  24. age: 42,
  25. address: 'London No. 1 Lake Park',
  26. description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.',
  27. },
  28. {
  29. key: 3,
  30. name: 'Joe Black',
  31. age: 32,
  32. address: 'Sidney No. 1 Lake Park',
  33. description: 'My name is Joe Black, I am 32 years old, living in Sidney No. 1 Lake Park.',
  34. },
  35. ];
  36. ReactDOM.render(
  37. <Table
  38. columns={columns}
  39. expandedRowRender={record => <p style={{ margin: 0 }}>{record.description}</p>}
  40. dataSource={data}
  41. />,
  42. mountNode,
  43. );

Table表格 - 图13

表格行/列合并

表头只支持列合并,使用 column 里的 colSpan 进行设置。

表格支持行/列合并,使用 render 里的单元格属性 colSpan 或者 rowSpan 设值为 0 时,设置的表格不会渲染。

  1. import { Table } from 'antd';
  2. // In the fifth row, other columns are merged into first column
  3. // by setting it's colSpan to be 0
  4. const renderContent = (value, row, index) => {
  5. const obj = {
  6. children: value,
  7. props: {},
  8. };
  9. if (index === 4) {
  10. obj.props.colSpan = 0;
  11. }
  12. return obj;
  13. };
  14. const columns = [
  15. {
  16. title: 'Name',
  17. dataIndex: 'name',
  18. render: (text, row, index) => {
  19. if (index < 4) {
  20. return <a>{text}</a>;
  21. }
  22. return {
  23. children: <a>{text}</a>,
  24. props: {
  25. colSpan: 5,
  26. },
  27. };
  28. },
  29. },
  30. {
  31. title: 'Age',
  32. dataIndex: 'age',
  33. render: renderContent,
  34. },
  35. {
  36. title: 'Home phone',
  37. colSpan: 2,
  38. dataIndex: 'tel',
  39. render: (value, row, index) => {
  40. const obj = {
  41. children: value,
  42. props: {},
  43. };
  44. if (index === 2) {
  45. obj.props.rowSpan = 2;
  46. }
  47. // These two are merged into above cell
  48. if (index === 3) {
  49. obj.props.rowSpan = 0;
  50. }
  51. if (index === 4) {
  52. obj.props.colSpan = 0;
  53. }
  54. return obj;
  55. },
  56. },
  57. {
  58. title: 'Phone',
  59. colSpan: 0,
  60. dataIndex: 'phone',
  61. render: renderContent,
  62. },
  63. {
  64. title: 'Address',
  65. dataIndex: 'address',
  66. render: renderContent,
  67. },
  68. ];
  69. const data = [
  70. {
  71. key: '1',
  72. name: 'John Brown',
  73. age: 32,
  74. tel: '0571-22098909',
  75. phone: 18889898989,
  76. address: 'New York No. 1 Lake Park',
  77. },
  78. {
  79. key: '2',
  80. name: 'Jim Green',
  81. tel: '0571-22098333',
  82. phone: 18889898888,
  83. age: 42,
  84. address: 'London No. 1 Lake Park',
  85. },
  86. {
  87. key: '3',
  88. name: 'Joe Black',
  89. age: 32,
  90. tel: '0575-22098909',
  91. phone: 18900010002,
  92. address: 'Sidney No. 1 Lake Park',
  93. },
  94. {
  95. key: '4',
  96. name: 'Jim Red',
  97. age: 18,
  98. tel: '0575-22098909',
  99. phone: 18900010002,
  100. address: 'London No. 2 Lake Park',
  101. },
  102. {
  103. key: '5',
  104. name: 'Jake White',
  105. age: 18,
  106. tel: '0575-22098909',
  107. phone: 18900010002,
  108. address: 'Dublin No. 2 Lake Park',
  109. },
  110. ];
  111. ReactDOM.render(<Table columns={columns} dataSource={data} bordered />, mountNode);

Table表格 - 图14

树形数据展示

表格支持树形数据的展示,当数据中有 children 字段时会自动展示为树形表格,如果不需要或配置为其他字段可以用 childrenColumnName 进行配置。

可以通过设置 indentSize 以控制每一层的缩进宽度。

注:暂不支持父子数据递归关联选择。

  1. import { Table } from 'antd';
  2. const columns = [
  3. {
  4. title: 'Name',
  5. dataIndex: 'name',
  6. key: 'name',
  7. },
  8. {
  9. title: 'Age',
  10. dataIndex: 'age',
  11. key: 'age',
  12. width: '12%',
  13. },
  14. {
  15. title: 'Address',
  16. dataIndex: 'address',
  17. width: '30%',
  18. key: 'address',
  19. },
  20. ];
  21. const data = [
  22. {
  23. key: 1,
  24. name: 'John Brown sr.',
  25. age: 60,
  26. address: 'New York No. 1 Lake Park',
  27. children: [
  28. {
  29. key: 11,
  30. name: 'John Brown',
  31. age: 42,
  32. address: 'New York No. 2 Lake Park',
  33. },
  34. {
  35. key: 12,
  36. name: 'John Brown jr.',
  37. age: 30,
  38. address: 'New York No. 3 Lake Park',
  39. children: [
  40. {
  41. key: 121,
  42. name: 'Jimmy Brown',
  43. age: 16,
  44. address: 'New York No. 3 Lake Park',
  45. },
  46. ],
  47. },
  48. {
  49. key: 13,
  50. name: 'Jim Green sr.',
  51. age: 72,
  52. address: 'London No. 1 Lake Park',
  53. children: [
  54. {
  55. key: 131,
  56. name: 'Jim Green',
  57. age: 42,
  58. address: 'London No. 2 Lake Park',
  59. children: [
  60. {
  61. key: 1311,
  62. name: 'Jim Green jr.',
  63. age: 25,
  64. address: 'London No. 3 Lake Park',
  65. },
  66. {
  67. key: 1312,
  68. name: 'Jimmy Green sr.',
  69. age: 18,
  70. address: 'London No. 4 Lake Park',
  71. },
  72. ],
  73. },
  74. ],
  75. },
  76. ],
  77. },
  78. {
  79. key: 2,
  80. name: 'Joe Black',
  81. age: 32,
  82. address: 'Sidney No. 1 Lake Park',
  83. },
  84. ];
  85. // rowSelection objects indicates the need for row selection
  86. const rowSelection = {
  87. onChange: (selectedRowKeys, selectedRows) => {
  88. console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
  89. },
  90. onSelect: (record, selected, selectedRows) => {
  91. console.log(record, selected, selectedRows);
  92. },
  93. onSelectAll: (selected, selectedRows, changeRows) => {
  94. console.log(selected, selectedRows, changeRows);
  95. },
  96. };
  97. ReactDOM.render(
  98. <Table columns={columns} rowSelection={rowSelection} dataSource={data} />,
  99. mountNode,
  100. );

Table表格 - 图15

固定表头

方便一页内展示大量数据。

需要指定 column 的 width 属性,否则列头和内容可能不对齐。如果指定 width 不生效或出现白色垂直空隙,请尝试建议留一列不设宽度以适应弹性布局,或者检查是否有超长连续字段破坏布局

  1. import { Table } from 'antd';
  2. const columns = [
  3. {
  4. title: 'Name',
  5. dataIndex: 'name',
  6. width: 150,
  7. },
  8. {
  9. title: 'Age',
  10. dataIndex: 'age',
  11. width: 150,
  12. },
  13. {
  14. title: 'Address',
  15. dataIndex: 'address',
  16. },
  17. ];
  18. const data = [];
  19. for (let i = 0; i < 100; i++) {
  20. data.push({
  21. key: i,
  22. name: `Edward King ${i}`,
  23. age: 32,
  24. address: `London, Park Lane no. ${i}`,
  25. });
  26. }
  27. ReactDOM.render(
  28. <Table columns={columns} dataSource={data} pagination={{ pageSize: 50 }} scroll={{ y: 240 }} />,
  29. mountNode,
  30. );

Table表格 - 图16

固定列

对于列数很多的数据,可以固定前后的列,横向滚动查看其它数据,需要和 scroll.x 配合使用。

若列头与内容不对齐或出现列重复,请指定固定列的宽度 width。如果指定 width 不生效或出现白色垂直空隙,请尝试建议留一列不设宽度以适应弹性布局,或者检查是否有超长连续字段破坏布局

建议指定 scroll.x 为大于表格宽度的固定值或百分比。注意,且非固定列宽度之和不要超过 scroll.x

  1. import { Table } from 'antd';
  2. const columns = [
  3. {
  4. title: 'Full Name',
  5. width: 100,
  6. dataIndex: 'name',
  7. key: 'name',
  8. fixed: 'left',
  9. },
  10. {
  11. title: 'Age',
  12. width: 100,
  13. dataIndex: 'age',
  14. key: 'age',
  15. fixed: 'left',
  16. },
  17. { title: 'Column 1', dataIndex: 'address', key: '1' },
  18. { title: 'Column 2', dataIndex: 'address', key: '2' },
  19. { title: 'Column 3', dataIndex: 'address', key: '3' },
  20. { title: 'Column 4', dataIndex: 'address', key: '4' },
  21. { title: 'Column 5', dataIndex: 'address', key: '5' },
  22. { title: 'Column 6', dataIndex: 'address', key: '6' },
  23. { title: 'Column 7', dataIndex: 'address', key: '7' },
  24. { title: 'Column 8', dataIndex: 'address', key: '8' },
  25. {
  26. title: 'Action',
  27. key: 'operation',
  28. fixed: 'right',
  29. width: 100,
  30. render: () => <a>action</a>,
  31. },
  32. ];
  33. const data = [
  34. {
  35. key: '1',
  36. name: 'John Brown',
  37. age: 32,
  38. address: 'New York Park',
  39. },
  40. {
  41. key: '2',
  42. name: 'Jim Green',
  43. age: 40,
  44. address: 'London Park',
  45. },
  46. ];
  47. ReactDOM.render(<Table columns={columns} dataSource={data} scroll={{ x: 1300 }} />, mountNode);

Table表格 - 图17

固定头和列

适合同时展示有大量数据和数据列。

若列头与内容不对齐或出现列重复,请指定固定列的宽度 width。如果指定 width 不生效或出现白色垂直空隙,请尝试建议留一列不设宽度以适应弹性布局,或者检查是否有超长连续字段破坏布局

建议指定 scroll.x 为大于表格宽度的固定值或百分比。注意,且非固定列宽度之和不要超过 scroll.x

  1. import { Table } from 'antd';
  2. const columns = [
  3. {
  4. title: 'Full Name',
  5. width: 100,
  6. dataIndex: 'name',
  7. key: 'name',
  8. fixed: 'left',
  9. },
  10. {
  11. title: 'Age',
  12. width: 100,
  13. dataIndex: 'age',
  14. key: 'age',
  15. fixed: 'left',
  16. },
  17. {
  18. title: 'Column 1',
  19. dataIndex: 'address',
  20. key: '1',
  21. width: 150,
  22. },
  23. {
  24. title: 'Column 2',
  25. dataIndex: 'address',
  26. key: '2',
  27. width: 150,
  28. },
  29. {
  30. title: 'Column 3',
  31. dataIndex: 'address',
  32. key: '3',
  33. width: 150,
  34. },
  35. {
  36. title: 'Column 4',
  37. dataIndex: 'address',
  38. key: '4',
  39. width: 150,
  40. },
  41. {
  42. title: 'Column 5',
  43. dataIndex: 'address',
  44. key: '5',
  45. width: 150,
  46. },
  47. {
  48. title: 'Column 6',
  49. dataIndex: 'address',
  50. key: '6',
  51. width: 150,
  52. },
  53. {
  54. title: 'Column 7',
  55. dataIndex: 'address',
  56. key: '7',
  57. width: 150,
  58. },
  59. { title: 'Column 8', dataIndex: 'address', key: '8' },
  60. {
  61. title: 'Action',
  62. key: 'operation',
  63. fixed: 'right',
  64. width: 100,
  65. render: () => <a>action</a>,
  66. },
  67. ];
  68. const data = [];
  69. for (let i = 0; i < 100; i++) {
  70. data.push({
  71. key: i,
  72. name: `Edrward ${i}`,
  73. age: 32,
  74. address: `London Park no. ${i}`,
  75. });
  76. }
  77. ReactDOM.render(
  78. <Table columns={columns} dataSource={data} scroll={{ x: 1500, y: 300 }} />,
  79. mountNode,
  80. );

Table表格 - 图18

表头分组

columns[n] 可以内嵌 children,以渲染分组表头。

  1. import { Table } from 'antd';
  2. const columns = [
  3. {
  4. title: 'Name',
  5. dataIndex: 'name',
  6. key: 'name',
  7. width: 100,
  8. fixed: 'left',
  9. filters: [
  10. {
  11. text: 'Joe',
  12. value: 'Joe',
  13. },
  14. {
  15. text: 'John',
  16. value: 'John',
  17. },
  18. ],
  19. onFilter: (value, record) => record.name.indexOf(value) === 0,
  20. },
  21. {
  22. title: 'Other',
  23. children: [
  24. {
  25. title: 'Age',
  26. dataIndex: 'age',
  27. key: 'age',
  28. width: 150,
  29. sorter: (a, b) => a.age - b.age,
  30. },
  31. {
  32. title: 'Address',
  33. children: [
  34. {
  35. title: 'Street',
  36. dataIndex: 'street',
  37. key: 'street',
  38. width: 150,
  39. },
  40. {
  41. title: 'Block',
  42. children: [
  43. {
  44. title: 'Building',
  45. dataIndex: 'building',
  46. key: 'building',
  47. width: 100,
  48. },
  49. {
  50. title: 'Door No.',
  51. dataIndex: 'number',
  52. key: 'number',
  53. width: 100,
  54. },
  55. ],
  56. },
  57. ],
  58. },
  59. ],
  60. },
  61. {
  62. title: 'Company',
  63. children: [
  64. {
  65. title: 'Company Address',
  66. dataIndex: 'companyAddress',
  67. key: 'companyAddress',
  68. width: 200,
  69. },
  70. {
  71. title: 'Company Name',
  72. dataIndex: 'companyName',
  73. key: 'companyName',
  74. },
  75. ],
  76. },
  77. {
  78. title: 'Gender',
  79. dataIndex: 'gender',
  80. key: 'gender',
  81. width: 80,
  82. fixed: 'right',
  83. },
  84. ];
  85. const data = [];
  86. for (let i = 0; i < 100; i++) {
  87. data.push({
  88. key: i,
  89. name: 'John Brown',
  90. age: i + 1,
  91. street: 'Lake Park',
  92. building: 'C',
  93. number: 2035,
  94. companyAddress: 'Lake Street 42',
  95. companyName: 'SoftLake Co',
  96. gender: 'M',
  97. });
  98. }
  99. ReactDOM.render(
  100. <Table
  101. columns={columns}
  102. dataSource={data}
  103. bordered
  104. size="middle"
  105. scroll={{ x: 'calc(700px + 50%)', y: 240 }}
  106. />,
  107. mountNode,
  108. );

Table表格 - 图19

可编辑单元格

带单元格编辑功能的表格。

  1. import { Table, Input, Button, Popconfirm, Form } from 'antd';
  2. const EditableContext = React.createContext();
  3. const EditableRow = ({ form, index, ...props }) => (
  4. <EditableContext.Provider value={form}>
  5. <tr {...props} />
  6. </EditableContext.Provider>
  7. );
  8. const EditableFormRow = Form.create()(EditableRow);
  9. class EditableCell extends React.Component {
  10. state = {
  11. editing: false,
  12. };
  13. toggleEdit = () => {
  14. const editing = !this.state.editing;
  15. this.setState({ editing }, () => {
  16. if (editing) {
  17. this.input.focus();
  18. }
  19. });
  20. };
  21. save = e => {
  22. const { record, handleSave } = this.props;
  23. this.form.validateFields((error, values) => {
  24. if (error && error[e.currentTarget.id]) {
  25. return;
  26. }
  27. this.toggleEdit();
  28. handleSave({ ...record, ...values });
  29. });
  30. };
  31. renderCell = form => {
  32. this.form = form;
  33. const { children, dataIndex, record, title } = this.props;
  34. const { editing } = this.state;
  35. return editing ? (
  36. <Form.Item style={{ margin: 0 }}>
  37. {form.getFieldDecorator(dataIndex, {
  38. rules: [
  39. {
  40. required: true,
  41. message: `${title} is required.`,
  42. },
  43. ],
  44. initialValue: record[dataIndex],
  45. })(<Input ref={node => (this.input = node)} onPressEnter={this.save} onBlur={this.save} />)}
  46. </Form.Item>
  47. ) : (
  48. <div
  49. className="editable-cell-value-wrap"
  50. style={{ paddingRight: 24 }}
  51. onClick={this.toggleEdit}
  52. >
  53. {children}
  54. </div>
  55. );
  56. };
  57. render() {
  58. const {
  59. editable,
  60. dataIndex,
  61. title,
  62. record,
  63. index,
  64. handleSave,
  65. children,
  66. ...restProps
  67. } = this.props;
  68. return (
  69. <td {...restProps}>
  70. {editable ? (
  71. <EditableContext.Consumer>{this.renderCell}</EditableContext.Consumer>
  72. ) : (
  73. children
  74. )}
  75. </td>
  76. );
  77. }
  78. }
  79. class EditableTable extends React.Component {
  80. constructor(props) {
  81. super(props);
  82. this.columns = [
  83. {
  84. title: 'name',
  85. dataIndex: 'name',
  86. width: '30%',
  87. editable: true,
  88. },
  89. {
  90. title: 'age',
  91. dataIndex: 'age',
  92. },
  93. {
  94. title: 'address',
  95. dataIndex: 'address',
  96. },
  97. {
  98. title: 'operation',
  99. dataIndex: 'operation',
  100. render: (text, record) =>
  101. this.state.dataSource.length >= 1 ? (
  102. <Popconfirm title="Sure to delete?" onConfirm={() => this.handleDelete(record.key)}>
  103. <a>Delete</a>
  104. </Popconfirm>
  105. ) : null,
  106. },
  107. ];
  108. this.state = {
  109. dataSource: [
  110. {
  111. key: '0',
  112. name: 'Edward King 0',
  113. age: '32',
  114. address: 'London, Park Lane no. 0',
  115. },
  116. {
  117. key: '1',
  118. name: 'Edward King 1',
  119. age: '32',
  120. address: 'London, Park Lane no. 1',
  121. },
  122. ],
  123. count: 2,
  124. };
  125. }
  126. handleDelete = key => {
  127. const dataSource = [...this.state.dataSource];
  128. this.setState({ dataSource: dataSource.filter(item => item.key !== key) });
  129. };
  130. handleAdd = () => {
  131. const { count, dataSource } = this.state;
  132. const newData = {
  133. key: count,
  134. name: `Edward King ${count}`,
  135. age: 32,
  136. address: `London, Park Lane no. ${count}`,
  137. };
  138. this.setState({
  139. dataSource: [...dataSource, newData],
  140. count: count + 1,
  141. });
  142. };
  143. handleSave = row => {
  144. const newData = [...this.state.dataSource];
  145. const index = newData.findIndex(item => row.key === item.key);
  146. const item = newData[index];
  147. newData.splice(index, 1, {
  148. ...item,
  149. ...row,
  150. });
  151. this.setState({ dataSource: newData });
  152. };
  153. render() {
  154. const { dataSource } = this.state;
  155. const components = {
  156. body: {
  157. row: EditableFormRow,
  158. cell: EditableCell,
  159. },
  160. };
  161. const columns = this.columns.map(col => {
  162. if (!col.editable) {
  163. return col;
  164. }
  165. return {
  166. ...col,
  167. onCell: record => ({
  168. record,
  169. editable: col.editable,
  170. dataIndex: col.dataIndex,
  171. title: col.title,
  172. handleSave: this.handleSave,
  173. }),
  174. };
  175. });
  176. return (
  177. <div>
  178. <Button onClick={this.handleAdd} type="primary" style={{ marginBottom: 16 }}>
  179. Add a row
  180. </Button>
  181. <Table
  182. components={components}
  183. rowClassName={() => 'editable-row'}
  184. bordered
  185. dataSource={dataSource}
  186. columns={columns}
  187. />
  188. </div>
  189. );
  190. }
  191. }
  192. ReactDOM.render(<EditableTable />, mountNode);
  1. .editable-cell {
  2. position: relative;
  3. }
  4. .editable-cell-value-wrap {
  5. padding: 5px 12px;
  6. cursor: pointer;
  7. }
  8. .editable-row:hover .editable-cell-value-wrap {
  9. border: 1px solid #d9d9d9;
  10. border-radius: 4px;
  11. padding: 4px 11px;
  12. }

Table表格 - 图20

可编辑行

带行编辑功能的表格。

  1. import { Table, Input, InputNumber, Popconfirm, Form } from 'antd';
  2. const data = [];
  3. for (let i = 0; i < 100; i++) {
  4. data.push({
  5. key: i.toString(),
  6. name: `Edrward ${i}`,
  7. age: 32,
  8. address: `London Park no. ${i}`,
  9. });
  10. }
  11. const EditableContext = React.createContext();
  12. class EditableCell extends React.Component {
  13. getInput = () => {
  14. if (this.props.inputType === 'number') {
  15. return <InputNumber />;
  16. }
  17. return <Input />;
  18. };
  19. renderCell = ({ getFieldDecorator }) => {
  20. const {
  21. editing,
  22. dataIndex,
  23. title,
  24. inputType,
  25. record,
  26. index,
  27. children,
  28. ...restProps
  29. } = this.props;
  30. return (
  31. <td {...restProps}>
  32. {editing ? (
  33. <Form.Item style={{ margin: 0 }}>
  34. {getFieldDecorator(dataIndex, {
  35. rules: [
  36. {
  37. required: true,
  38. message: `Please Input ${title}!`,
  39. },
  40. ],
  41. initialValue: record[dataIndex],
  42. })(this.getInput())}
  43. </Form.Item>
  44. ) : (
  45. children
  46. )}
  47. </td>
  48. );
  49. };
  50. render() {
  51. return <EditableContext.Consumer>{this.renderCell}</EditableContext.Consumer>;
  52. }
  53. }
  54. class EditableTable extends React.Component {
  55. constructor(props) {
  56. super(props);
  57. this.state = { data, editingKey: '' };
  58. this.columns = [
  59. {
  60. title: 'name',
  61. dataIndex: 'name',
  62. width: '25%',
  63. editable: true,
  64. },
  65. {
  66. title: 'age',
  67. dataIndex: 'age',
  68. width: '15%',
  69. editable: true,
  70. },
  71. {
  72. title: 'address',
  73. dataIndex: 'address',
  74. width: '40%',
  75. editable: true,
  76. },
  77. {
  78. title: 'operation',
  79. dataIndex: 'operation',
  80. render: (text, record) => {
  81. const { editingKey } = this.state;
  82. const editable = this.isEditing(record);
  83. return editable ? (
  84. <span>
  85. <EditableContext.Consumer>
  86. {form => (
  87. <a
  88. onClick={() => this.save(form, record.key)}
  89. style={{ marginRight: 8 }}
  90. >
  91. Save
  92. </a>
  93. )}
  94. </EditableContext.Consumer>
  95. <Popconfirm title="Sure to cancel?" onConfirm={() => this.cancel(record.key)}>
  96. <a>Cancel</a>
  97. </Popconfirm>
  98. </span>
  99. ) : (
  100. <a disabled={editingKey !== ''} onClick={() => this.edit(record.key)}>
  101. Edit
  102. </a>
  103. );
  104. },
  105. },
  106. ];
  107. }
  108. isEditing = record => record.key === this.state.editingKey;
  109. cancel = () => {
  110. this.setState({ editingKey: '' });
  111. };
  112. save(form, key) {
  113. form.validateFields((error, row) => {
  114. if (error) {
  115. return;
  116. }
  117. const newData = [...this.state.data];
  118. const index = newData.findIndex(item => key === item.key);
  119. if (index > -1) {
  120. const item = newData[index];
  121. newData.splice(index, 1, {
  122. ...item,
  123. ...row,
  124. });
  125. this.setState({ data: newData, editingKey: '' });
  126. } else {
  127. newData.push(row);
  128. this.setState({ data: newData, editingKey: '' });
  129. }
  130. });
  131. }
  132. edit(key) {
  133. this.setState({ editingKey: key });
  134. }
  135. render() {
  136. const components = {
  137. body: {
  138. cell: EditableCell,
  139. },
  140. };
  141. const columns = this.columns.map(col => {
  142. if (!col.editable) {
  143. return col;
  144. }
  145. return {
  146. ...col,
  147. onCell: record => ({
  148. record,
  149. inputType: col.dataIndex === 'age' ? 'number' : 'text',
  150. dataIndex: col.dataIndex,
  151. title: col.title,
  152. editing: this.isEditing(record),
  153. }),
  154. };
  155. });
  156. return (
  157. <EditableContext.Provider value={this.props.form}>
  158. <Table
  159. components={components}
  160. bordered
  161. dataSource={this.state.data}
  162. columns={columns}
  163. rowClassName="editable-row"
  164. pagination={{
  165. onChange: this.cancel,
  166. }}
  167. />
  168. </EditableContext.Provider>
  169. );
  170. }
  171. }
  172. const EditableFormTable = Form.create()(EditableTable);
  173. ReactDOM.render(<EditableFormTable />, mountNode);
  1. .editable-row .ant-form-explain {
  2. position: absolute;
  3. font-size: 12px;
  4. margin-top: -4px;
  5. }

Table表格 - 图21

嵌套子表格

展示每行数据更详细的信息。

  1. import { Table, Badge, Menu, Dropdown, Icon } from 'antd';
  2. const menu = (
  3. <Menu>
  4. <Menu.Item>Action 1</Menu.Item>
  5. <Menu.Item>Action 2</Menu.Item>
  6. </Menu>
  7. );
  8. function NestedTable() {
  9. const expandedRowRender = () => {
  10. const columns = [
  11. { title: 'Date', dataIndex: 'date', key: 'date' },
  12. { title: 'Name', dataIndex: 'name', key: 'name' },
  13. {
  14. title: 'Status',
  15. key: 'state',
  16. render: () => (
  17. <span>
  18. <Badge status="success" />
  19. Finished
  20. </span>
  21. ),
  22. },
  23. { title: 'Upgrade Status', dataIndex: 'upgradeNum', key: 'upgradeNum' },
  24. {
  25. title: 'Action',
  26. dataIndex: 'operation',
  27. key: 'operation',
  28. render: () => (
  29. <span className="table-operation">
  30. <a>Pause</a>
  31. <a>Stop</a>
  32. <Dropdown overlay={menu}>
  33. <a>
  34. More <Icon type="down" />
  35. </a>
  36. </Dropdown>
  37. </span>
  38. ),
  39. },
  40. ];
  41. const data = [];
  42. for (let i = 0; i < 3; ++i) {
  43. data.push({
  44. key: i,
  45. date: '2014-12-24 23:12:00',
  46. name: 'This is production name',
  47. upgradeNum: 'Upgraded: 56',
  48. });
  49. }
  50. return <Table columns={columns} dataSource={data} pagination={false} />;
  51. };
  52. const columns = [
  53. { title: 'Name', dataIndex: 'name', key: 'name' },
  54. { title: 'Platform', dataIndex: 'platform', key: 'platform' },
  55. { title: 'Version', dataIndex: 'version', key: 'version' },
  56. { title: 'Upgraded', dataIndex: 'upgradeNum', key: 'upgradeNum' },
  57. { title: 'Creator', dataIndex: 'creator', key: 'creator' },
  58. { title: 'Date', dataIndex: 'createdAt', key: 'createdAt' },
  59. { title: 'Action', key: 'operation', render: () => <a>Publish</a> },
  60. ];
  61. const data = [];
  62. for (let i = 0; i < 3; ++i) {
  63. data.push({
  64. key: i,
  65. name: 'Screem',
  66. platform: 'iOS',
  67. version: '10.3.4.5654',
  68. upgradeNum: 500,
  69. creator: 'Jack',
  70. createdAt: '2014-12-24 23:12:00',
  71. });
  72. }
  73. return (
  74. <Table
  75. className="components-table-demo-nested"
  76. columns={columns}
  77. expandedRowRender={expandedRowRender}
  78. dataSource={data}
  79. />
  80. );
  81. }
  82. ReactDOM.render(<NestedTable />, mountNode);

Table表格 - 图22

拖拽排序

使用自定义元素,我们可以集成 react-dnd 来实现拖拽排序。

  1. import { Table } from 'antd';
  2. import { DndProvider, DragSource, DropTarget } from 'react-dnd';
  3. import HTML5Backend from 'react-dnd-html5-backend';
  4. import update from 'immutability-helper';
  5. let dragingIndex = -1;
  6. class BodyRow extends React.Component {
  7. render() {
  8. const { isOver, connectDragSource, connectDropTarget, moveRow, ...restProps } = this.props;
  9. const style = { ...restProps.style, cursor: 'move' };
  10. let { className } = restProps;
  11. if (isOver) {
  12. if (restProps.index > dragingIndex) {
  13. className += ' drop-over-downward';
  14. }
  15. if (restProps.index < dragingIndex) {
  16. className += ' drop-over-upward';
  17. }
  18. }
  19. return connectDragSource(
  20. connectDropTarget(<tr {...restProps} className={className} style={style} />),
  21. );
  22. }
  23. }
  24. const rowSource = {
  25. beginDrag(props) {
  26. dragingIndex = props.index;
  27. return {
  28. index: props.index,
  29. };
  30. },
  31. };
  32. const rowTarget = {
  33. drop(props, monitor) {
  34. const dragIndex = monitor.getItem().index;
  35. const hoverIndex = props.index;
  36. // Don't replace items with themselves
  37. if (dragIndex === hoverIndex) {
  38. return;
  39. }
  40. // Time to actually perform the action
  41. props.moveRow(dragIndex, hoverIndex);
  42. // Note: we're mutating the monitor item here!
  43. // Generally it's better to avoid mutations,
  44. // but it's good here for the sake of performance
  45. // to avoid expensive index searches.
  46. monitor.getItem().index = hoverIndex;
  47. },
  48. };
  49. const DragableBodyRow = DropTarget('row', rowTarget, (connect, monitor) => ({
  50. connectDropTarget: connect.dropTarget(),
  51. isOver: monitor.isOver(),
  52. }))(
  53. DragSource('row', rowSource, connect => ({
  54. connectDragSource: connect.dragSource(),
  55. }))(BodyRow),
  56. );
  57. const columns = [
  58. {
  59. title: 'Name',
  60. dataIndex: 'name',
  61. key: 'name',
  62. },
  63. {
  64. title: 'Age',
  65. dataIndex: 'age',
  66. key: 'age',
  67. },
  68. {
  69. title: 'Address',
  70. dataIndex: 'address',
  71. key: 'address',
  72. },
  73. ];
  74. class DragSortingTable extends React.Component {
  75. state = {
  76. data: [
  77. {
  78. key: '1',
  79. name: 'John Brown',
  80. age: 32,
  81. address: 'New York No. 1 Lake Park',
  82. },
  83. {
  84. key: '2',
  85. name: 'Jim Green',
  86. age: 42,
  87. address: 'London No. 1 Lake Park',
  88. },
  89. {
  90. key: '3',
  91. name: 'Joe Black',
  92. age: 32,
  93. address: 'Sidney No. 1 Lake Park',
  94. },
  95. ],
  96. };
  97. components = {
  98. body: {
  99. row: DragableBodyRow,
  100. },
  101. };
  102. moveRow = (dragIndex, hoverIndex) => {
  103. const { data } = this.state;
  104. const dragRow = data[dragIndex];
  105. this.setState(
  106. update(this.state, {
  107. data: {
  108. $splice: [[dragIndex, 1], [hoverIndex, 0, dragRow]],
  109. },
  110. }),
  111. );
  112. };
  113. render() {
  114. return (
  115. <DndProvider backend={HTML5Backend}>
  116. <Table
  117. columns={columns}
  118. dataSource={this.state.data}
  119. components={this.components}
  120. onRow={(record, index) => ({
  121. index,
  122. moveRow: this.moveRow,
  123. })}
  124. />
  125. </DndProvider>
  126. );
  127. }
  128. }
  129. ReactDOM.render(<DragSortingTable />, mountNode);
  1. #components-table-demo-drag-sorting tr.drop-over-downward td {
  2. border-bottom: 2px dashed #1890ff;
  3. }
  4. #components-table-demo-drag-sorting tr.drop-over-upward td {
  5. border-top: 2px dashed #1890ff;
  6. }

Table表格 - 图23

可伸缩列

集成 react-resizable 来实现可伸缩列。

  1. import { Table } from 'antd';
  2. import { Resizable } from 'react-resizable';
  3. const ResizeableTitle = props => {
  4. const { onResize, width, ...restProps } = props;
  5. if (!width) {
  6. return <th {...restProps} />;
  7. }
  8. return (
  9. <Resizable
  10. width={width}
  11. height={0}
  12. onResize={onResize}
  13. draggableOpts={{ enableUserSelectHack: false }}
  14. >
  15. <th {...restProps} />
  16. </Resizable>
  17. );
  18. };
  19. class Demo extends React.Component {
  20. state = {
  21. columns: [
  22. {
  23. title: 'Date',
  24. dataIndex: 'date',
  25. width: 200,
  26. },
  27. {
  28. title: 'Amount',
  29. dataIndex: 'amount',
  30. width: 100,
  31. },
  32. {
  33. title: 'Type',
  34. dataIndex: 'type',
  35. width: 100,
  36. },
  37. {
  38. title: 'Note',
  39. dataIndex: 'note',
  40. width: 100,
  41. },
  42. {
  43. title: 'Action',
  44. key: 'action',
  45. render: () => <a>Delete</a>,
  46. },
  47. ],
  48. };
  49. components = {
  50. header: {
  51. cell: ResizeableTitle,
  52. },
  53. };
  54. data = [
  55. {
  56. key: 0,
  57. date: '2018-02-11',
  58. amount: 120,
  59. type: 'income',
  60. note: 'transfer',
  61. },
  62. {
  63. key: 1,
  64. date: '2018-03-11',
  65. amount: 243,
  66. type: 'income',
  67. note: 'transfer',
  68. },
  69. {
  70. key: 2,
  71. date: '2018-04-11',
  72. amount: 98,
  73. type: 'income',
  74. note: 'transfer',
  75. },
  76. ];
  77. handleResize = index => (e, { size }) => {
  78. this.setState(({ columns }) => {
  79. const nextColumns = [...columns];
  80. nextColumns[index] = {
  81. ...nextColumns[index],
  82. width: size.width,
  83. };
  84. return { columns: nextColumns };
  85. });
  86. };
  87. render() {
  88. const columns = this.state.columns.map((col, index) => ({
  89. ...col,
  90. onHeaderCell: column => ({
  91. width: column.width,
  92. onResize: this.handleResize(index),
  93. }),
  94. }));
  95. return <Table bordered components={this.components} columns={columns} dataSource={this.data} />;
  96. }
  97. }
  98. ReactDOM.render(<Demo />, mountNode);
  1. #components-table-demo-resizable-column .react-resizable {
  2. position: relative;
  3. background-clip: padding-box;
  4. }
  5. #components-table-demo-resizable-column .react-resizable-handle {
  6. position: absolute;
  7. width: 10px;
  8. height: 100%;
  9. bottom: 0;
  10. right: -5px;
  11. cursor: col-resize;
  12. z-index: 1;
  13. }

Table表格 - 图24

单元格自动省略

设置 column.ellipsis 可以让单元格内容根据宽度自动省略。

列头缩略暂不支持和排序筛选一起使用。

  1. import { Table } from 'antd';
  2. const columns = [
  3. {
  4. title: 'Name',
  5. dataIndex: 'name',
  6. key: 'name',
  7. render: text => <a>{text}</a>,
  8. width: 150,
  9. },
  10. {
  11. title: 'Age',
  12. dataIndex: 'age',
  13. key: 'age',
  14. width: 80,
  15. },
  16. {
  17. title: 'Address',
  18. dataIndex: 'address',
  19. key: 'address 1',
  20. ellipsis: true,
  21. },
  22. {
  23. title: 'Long Column Long Column Long Column',
  24. dataIndex: 'address',
  25. key: 'address 2',
  26. ellipsis: true,
  27. },
  28. {
  29. title: 'Long Column Long Column',
  30. dataIndex: 'address',
  31. key: 'address 3',
  32. ellipsis: true,
  33. },
  34. {
  35. title: 'Long Column',
  36. dataIndex: 'address',
  37. key: 'address 4',
  38. ellipsis: true,
  39. },
  40. ];
  41. const data = [
  42. {
  43. key: '1',
  44. name: 'John Brown',
  45. age: 32,
  46. address: 'New York No. 1 Lake Park, New York No. 1 Lake Park',
  47. tags: ['nice', 'developer'],
  48. },
  49. {
  50. key: '2',
  51. name: 'Jim Green',
  52. age: 42,
  53. address: 'London No. 2 Lake Park, London No. 2 Lake Park',
  54. tags: ['loser'],
  55. },
  56. {
  57. key: '3',
  58. name: 'Joe Black',
  59. age: 32,
  60. address: 'Sidney No. 1 Lake Park, Sidney No. 1 Lake Park',
  61. tags: ['cool', 'teacher'],
  62. },
  63. ];
  64. ReactDOM.render(<Table columns={columns} dataSource={data} />, mountNode);

Table表格 - 图25

动态控制表格属性

选择不同配置组合查看效果。

  1. import { Table, Icon, Switch, Radio, Form, Divider } from 'antd';
  2. const columns = [
  3. {
  4. title: 'Name',
  5. dataIndex: 'name',
  6. key: 'name',
  7. render: text => <a>{text}</a>,
  8. },
  9. {
  10. title: 'Age',
  11. dataIndex: 'age',
  12. key: 'age',
  13. },
  14. {
  15. title: 'Address',
  16. dataIndex: 'address',
  17. key: 'address',
  18. },
  19. {
  20. title: 'Action',
  21. key: 'action',
  22. render: (text, record) => (
  23. <span>
  24. <a>Action {record.name}</a>
  25. <Divider type="vertical" />
  26. <a>Delete</a>
  27. <Divider type="vertical" />
  28. <a className="ant-dropdown-link">
  29. More actions <Icon type="down" />
  30. </a>
  31. </span>
  32. ),
  33. },
  34. ];
  35. const data = [];
  36. for (let i = 1; i <= 10; i++) {
  37. data.push({
  38. key: i,
  39. name: 'John Brown',
  40. age: `${i}2`,
  41. address: `New York No. ${i} Lake Park`,
  42. description: `My name is John Brown, I am ${i}2 years old, living in New York No. ${i} Lake Park.`,
  43. });
  44. }
  45. const expandedRowRender = record => <p>{record.description}</p>;
  46. const title = () => 'Here is title';
  47. const showHeader = true;
  48. const footer = () => 'Here is footer';
  49. const scroll = { y: 240 };
  50. const pagination = { position: 'bottom' };
  51. class Demo extends React.Component {
  52. state = {
  53. bordered: false,
  54. loading: false,
  55. pagination,
  56. size: 'default',
  57. expandedRowRender,
  58. title: undefined,
  59. showHeader,
  60. footer,
  61. rowSelection: {},
  62. scroll: undefined,
  63. hasData: true,
  64. tableLayout: undefined,
  65. };
  66. handleToggle = prop => enable => {
  67. this.setState({ [prop]: enable });
  68. };
  69. handleSizeChange = e => {
  70. this.setState({ size: e.target.value });
  71. };
  72. handleTableLayoutChange = e => {
  73. this.setState({ tableLayout: e.target.value });
  74. };
  75. handleExpandChange = enable => {
  76. this.setState({ expandedRowRender: enable ? expandedRowRender : undefined });
  77. };
  78. handleEllipsisChange = enable => {
  79. this.setState({ ellipsis: enable });
  80. };
  81. handleTitleChange = enable => {
  82. this.setState({ title: enable ? title : undefined });
  83. };
  84. handleHeaderChange = enable => {
  85. this.setState({ showHeader: enable ? showHeader : false });
  86. };
  87. handleFooterChange = enable => {
  88. this.setState({ footer: enable ? footer : undefined });
  89. };
  90. handleRowSelectionChange = enable => {
  91. this.setState({ rowSelection: enable ? {} : undefined });
  92. };
  93. handleScollChange = enable => {
  94. this.setState({ scroll: enable ? scroll : undefined });
  95. };
  96. handleDataChange = hasData => {
  97. this.setState({ hasData });
  98. };
  99. handlePaginationChange = e => {
  100. const { value } = e.target;
  101. this.setState({
  102. pagination: value === 'none' ? false : { position: value },
  103. });
  104. };
  105. render() {
  106. const { state } = this;
  107. return (
  108. <div>
  109. <Form
  110. layout="inline"
  111. className="components-table-demo-control-bar"
  112. style={{ marginBottom: 16 }}
  113. >
  114. <Form.Item label="Bordered">
  115. <Switch checked={state.bordered} onChange={this.handleToggle('bordered')} />
  116. </Form.Item>
  117. <Form.Item label="loading">
  118. <Switch checked={state.loading} onChange={this.handleToggle('loading')} />
  119. </Form.Item>
  120. <Form.Item label="Title">
  121. <Switch checked={!!state.title} onChange={this.handleTitleChange} />
  122. </Form.Item>
  123. <Form.Item label="Column Header">
  124. <Switch checked={!!state.showHeader} onChange={this.handleHeaderChange} />
  125. </Form.Item>
  126. <Form.Item label="Footer">
  127. <Switch checked={!!state.footer} onChange={this.handleFooterChange} />
  128. </Form.Item>
  129. <Form.Item label="Expandable">
  130. <Switch checked={!!state.expandedRowRender} onChange={this.handleExpandChange} />
  131. </Form.Item>
  132. <Form.Item label="Checkbox">
  133. <Switch checked={!!state.rowSelection} onChange={this.handleRowSelectionChange} />
  134. </Form.Item>
  135. <Form.Item label="Fixed Header">
  136. <Switch checked={!!state.scroll} onChange={this.handleScollChange} />
  137. </Form.Item>
  138. <Form.Item label="Has Data">
  139. <Switch checked={!!state.hasData} onChange={this.handleDataChange} />
  140. </Form.Item>
  141. <Form.Item label="Ellipsis">
  142. <Switch checked={!!state.ellipsis} onChange={this.handleEllipsisChange} />
  143. </Form.Item>
  144. <Form.Item label="Size">
  145. <Radio.Group value={state.size} onChange={this.handleSizeChange}>
  146. <Radio.Button value="default">Default</Radio.Button>
  147. <Radio.Button value="middle">Middle</Radio.Button>
  148. <Radio.Button value="small">Small</Radio.Button>
  149. </Radio.Group>
  150. </Form.Item>
  151. <Form.Item label="Table Layout">
  152. <Radio.Group value={state.tableLayout} onChange={this.handleTableLayoutChange}>
  153. <Radio.Button value={undefined}>Unset</Radio.Button>
  154. <Radio.Button value="fixed">Fixed</Radio.Button>
  155. </Radio.Group>
  156. </Form.Item>
  157. <Form.Item label="Pagination">
  158. <Radio.Group
  159. value={state.pagination ? state.pagination.position : 'none'}
  160. onChange={this.handlePaginationChange}
  161. >
  162. <Radio.Button value="top">Top</Radio.Button>
  163. <Radio.Button value="bottom">Bottom</Radio.Button>
  164. <Radio.Button value="both">Both</Radio.Button>
  165. <Radio.Button value="none">None</Radio.Button>
  166. </Radio.Group>
  167. </Form.Item>
  168. </Form>
  169. <Table
  170. {...this.state}
  171. columns={columns.map(item => ({ ...item, ellipsis: state. ellipsis }))}
  172. dataSource={state.hasData ? data : null}
  173. />
  174. </div>
  175. );
  176. }
  177. }
  178. ReactDOM.render(<Demo />, mountNode);

API

Table

参数说明类型默认值版本
tableLayout表格元素的 table-layout 属性,设为 fixed 表示内容不会影响列的布局- | 'auto' | 'fixed'无- - -固定表头/列或使用了 column.ellipsis 时,默认值为 fixed3.24.0
bordered是否展示外边框和列边框booleanfalse
childrenColumnName指定树形结构的列名string[]children3.4.2
columns表格列的配置描述,具体项见下表ColumnProps[]-
components覆盖默认的 table 元素TableComponents-
dataSource数据数组any[]
defaultExpandAllRows初始时,是否展开所有行booleanfalse
defaultExpandedRowKeys默认展开的行string[]-
expandedRowKeys展开的行,控制属性string[]-
expandedRowRender额外的展开行Function(record, index, indent, expanded):ReactNode-
expandIcon自定义展开图标,参考示例Function(props):ReactNode-3.11.3
expandRowByClick通过点击行来展开子行booleanfalse3.0.1
footer表格尾部Function(currentPageData)
indentSize展示树形数据时,每层缩进的宽度,以 px 为单位number15
loading页面是否加载中boolean|object (更多)false
locale默认文案设置,目前包括排序、过滤、空数据文案objectfilterConfirm: '确定' filterReset: '重置' emptyText: '暂无数据' 默认值
pagination分页器,参考配置项pagination 文档,设为 false 时不展示和进行分页object
rowClassName表格行的类名Function(record, index):string-
rowKey表格行 key 的取值,可以是字符串或一个函数string|Function(record):string'key'
rowSelection表格行是否可选择,配置项objectnull
scroll表格是否可滚动,配置项object-
showHeader是否显示表头booleantrue
size表格大小default | middle | smalldefault
title表格标题Function(currentPageData)
onChange分页、排序、筛选变化时触发Function(pagination, filters, sorter, extra: { currentDataSource: [] })
onExpand点击展开图标时触发Function(expanded, record)
onExpandedRowsChange展开的行变化时触发Function(expandedRows)
onHeaderRow设置头部行属性Function(column, index)-
onRow设置行属性Function(record, index)-
getPopupContainer设置表格内各类浮层的渲染节点,如筛选菜单(triggerNode) => HTMLElement() => TableHtmlElement3.21.0

onRow 用法

适用于 onRow onHeaderRow onCell onHeaderCell

  1. <Table
  2. onRow={record => {
  3. return {
  4. onClick: event => {}, // 点击行
  5. onDoubleClick: event => {},
  6. onContextMenu: event => {},
  7. onMouseEnter: event => {}, // 鼠标移入行
  8. onMouseLeave: event => {},
  9. };
  10. }}
  11. onHeaderRow={column => {
  12. return {
  13. onClick: () => {}, // 点击表头行
  14. };
  15. }}
  16. />

Column

列描述数据对象,是 columns 中的一项,Column 使用相同的 API。

参数说明类型默认值版本
align设置列的对齐方式'left' | 'right' | 'center''left'3.3.2
ellipsis超过宽度将自动省略,暂不支持和排序筛选一起使用。设置为 true 时,表格布局将变成 tableLayout="fixed"booleanfalse3.24.0
className列样式类名string-
colSpan表头列合并,设置为 0 时,不渲染number
dataIndex列数据在数据项中对应的 key,支持 a.b.ca[0].b.c[1] 的嵌套写法string-
defaultSortOrder默认排序顺序'ascend' | 'descend'-3.9.3
filterDropdown可以自定义筛选菜单,此函数只负责渲染图层,需要自行编写各种交互React.ReactNode | (props: FilterDropdownProps) => React.ReactNode-
filterDropdownVisible用于控制自定义筛选菜单是否可见boolean-
filtered标识数据是否经过过滤,筛选图标会高亮booleanfalse
filteredValue筛选的受控属性,外界可用此控制列的筛选状态,值为已筛选的 value 数组string[]-
filterIcon自定义 filter 图标。ReactNode|(filtered: boolean) => ReactNodefalse
filterMultiple是否多选booleantrue
filters表头的筛选菜单项object[]-
fixed列是否固定,可选 true(等效于 left) 'left' 'right'boolean|stringfalse
keyReact 需要的 key,如果已经设置了唯一的 dataIndex,可以忽略这个属性string-
render生成复杂数据的渲染函数,参数分别为当前行的值,当前行数据,行索引,@return 里面可以设置表格行/列合并Function(text, record, index) {}-
sorter排序函数,本地排序使用一个函数(参考 Array.sort 的 compareFunction),需要服务端排序可设为 trueFunction|boolean-
sortOrder排序的受控属性,外界可用此控制列的排序,可设置为 'ascend' 'descend' falseboolean|string-
sortDirections支持的排序方式,取值为 'ascend' 'descend'Array['ascend', 'descend']3.15.2
title列头显示文字(函数用法 3.10.0 后支持)ReactNode|({ sortOrder, sortColumn, filters }) => ReactNode-
width列宽度(指定了也不生效?string|number-
onCell设置单元格属性Function(record, rowIndex)-
onFilter本地模式下,确定筛选的运行函数Function-
onFilterDropdownVisibleChange自定义筛选菜单可见变化时调用function(visible) {}-
onHeaderCell设置头部单元格属性Function(column)-

ColumnGroup

参数说明类型默认值版本
title列头显示文字string|ReactNode-

pagination

分页的配置项。

参数说明类型默认值版本
position指定分页显示的位置'top' | 'bottom' | 'both''bottom'3.3.0

更多配置项,请查看 Pagination

rowSelection

选择功能的配置。

参数说明类型默认值版本
columnWidth自定义列表选择框宽度string|number60px3.3.0
columnTitle自定义列表选择框标题string|React.ReactNode-3.8.0
fixed把选择框列固定在左边boolean-
getCheckboxProps选择框的默认属性配置Function(record)-
hideDefaultSelections自定义选择项时去掉『全选』『反选』两个默认选项booleanfalse
selectedRowKeys指定选中项的 key 数组,需要和 onChange 进行配合string[]|number[][]
selections自定义选择项 配置项, 设为 true 时使用默认选择项object[]|booleantrue
type多选/单选,checkbox or radiostringcheckbox
onChange选中项发生变化时的回调Function(selectedRowKeys, selectedRows)-
onSelect用户手动选择/取消选择某行的回调Function(record, selected, selectedRows, nativeEvent)-
onSelectAll用户手动选择/取消选择所有行的回调Function(selected, selectedRows, changeRows)-
onSelectInvert用户手动选择反选的回调Function(selectedRows)-

scroll

参数说明类型默认值版本
x设置横向滚动,也可用于指定滚动区域的宽和高,可以设置为像素值,百分比,true 和 'max-content'number | true-
y设置纵向滚动,也可用于指定滚动区域的宽和高,可以设置为像素值,百分比,true 和 'max-content'number | true-
scrollToFirstRowOnChange当分页、排序、筛选变化后是否滚动到表格顶部boolean-3.24.0

selection

参数说明类型默认值版本
keyReact 需要的 key,建议设置string-
text选择项显示的文字string|React.ReactNode-
onSelect选择项点击回调Function(changeableRowKeys)-

在 TypeScript 中使用

import { Table } from 'antd';
import { ColumnProps } from 'antd/es/table';

interface User {
  key: number;
  name: string;
}

const columns: ColumnProps<User>[] = [{
  key: 'name',
  title: 'Name',
  dataIndex: 'name',
}];

const data: User[] = [{
  key: 0,
  name: 'Jack',
}];

class UserTable extends Table<User> {}
<UserTable columns={columns} dataSource={data} />

// 使用 JSX 风格的 API
class NameColumn extends Table.Column<User> {}

<UserTable dataSource={data}>
  <NameColumn key="name" title="Name" dataIndex="name" />
</UserTable>

// TypeScript 2.9 之后也可以这样写
// https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-9.html#generic-type-arguments-in-jsx-elements
<Table<User> columns={columns} dataSource={data} />
<Table<User> dataSource={data}>
  <Table.Column<User> key="name" title="Name" dataIndex="name" />
</Table>

注意

按照 React 的规范,所有的数组组件必须绑定 key。在 Table 中,dataSourcecolumns 里的数据值都需要指定 key 值。对于 dataSource 默认将每列数据的 key 属性作为唯一的标识。

控制台警告

如果 dataSource[i].key 没有提供,你应该使用 rowKey 来指定 dataSource 的主键,如下所示。若没有指定,控制台会出现以上的提示,表格组件也会出现各类奇怪的错误。

// 比如你的数据主键是 uid
return <Table rowKey="uid" />;
// 或
return <Table rowKey={record => record.uid} />;