Table 表格

展示行列数据。

何时使用

  • 当有大量结构化的数据需要展现时;
  • 当需要对数据进行排序、搜索、分页、自定义操作等复杂行为时。

如何使用

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

代码演示

Table表格 - 图1

基本用法

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

  1. <template>
  2. <a-table :columns="columns" :data-source="data">
  3. <a slot="name" slot-scope="text">{{ text }}</a>
  4. <span slot="customTitle"><a-icon type="smile-o" /> Name</span>
  5. <span slot="tags" slot-scope="tags">
  6. <a-tag
  7. v-for="tag in tags"
  8. :key="tag"
  9. :color="tag === 'loser' ? 'volcano' : tag.length > 5 ? 'geekblue' : 'green'"
  10. >
  11. {{ tag.toUpperCase() }}
  12. </a-tag>
  13. </span>
  14. <span slot="action" slot-scope="text, record">
  15. <a>Invite 一 {{ record.name }}</a>
  16. <a-divider type="vertical" />
  17. <a>Delete</a>
  18. <a-divider type="vertical" />
  19. <a class="ant-dropdown-link"> More actions <a-icon type="down" /> </a>
  20. </span>
  21. </a-table>
  22. </template>
  23. <script>
  24. const columns = [
  25. {
  26. dataIndex: 'name',
  27. key: 'name',
  28. slots: { title: 'customTitle' },
  29. scopedSlots: { customRender: 'name' },
  30. },
  31. {
  32. title: 'Age',
  33. dataIndex: 'age',
  34. key: 'age',
  35. },
  36. {
  37. title: 'Address',
  38. dataIndex: 'address',
  39. key: 'address',
  40. },
  41. {
  42. title: 'Tags',
  43. key: 'tags',
  44. dataIndex: 'tags',
  45. scopedSlots: { customRender: 'tags' },
  46. },
  47. {
  48. title: 'Action',
  49. key: 'action',
  50. scopedSlots: { customRender: 'action' },
  51. },
  52. ];
  53. const data = [
  54. {
  55. key: '1',
  56. name: 'John Brown',
  57. age: 32,
  58. address: 'New York No. 1 Lake Park',
  59. tags: ['nice', 'developer'],
  60. },
  61. {
  62. key: '2',
  63. name: 'Jim Green',
  64. age: 42,
  65. address: 'London No. 1 Lake Park',
  66. tags: ['loser'],
  67. },
  68. {
  69. key: '3',
  70. name: 'Joe Black',
  71. age: 32,
  72. address: 'Sidney No. 1 Lake Park',
  73. tags: ['cool', 'teacher'],
  74. },
  75. ];
  76. export default {
  77. data() {
  78. return {
  79. data,
  80. columns,
  81. };
  82. },
  83. };
  84. </script>

Table表格 - 图2

单元格自动省略

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

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

  1. <template>
  2. <a-table :columns="columns" :data-source="data">
  3. <a slot="name" slot-scope="text">{{ text }}</a>
  4. </a-table>
  5. </template>
  6. <script>
  7. const columns = [
  8. {
  9. title: 'Name',
  10. dataIndex: 'name',
  11. key: 'name',
  12. scopedSlots: { customRender: 'name' },
  13. },
  14. {
  15. title: 'Age',
  16. dataIndex: 'age',
  17. key: 'age',
  18. width: 80,
  19. },
  20. {
  21. title: 'Address',
  22. dataIndex: 'address',
  23. key: 'address 1',
  24. ellipsis: true,
  25. },
  26. {
  27. title: 'Long Column Long Column Long Column',
  28. dataIndex: 'address',
  29. key: 'address 2',
  30. ellipsis: true,
  31. },
  32. {
  33. title: 'Long Column Long Column',
  34. dataIndex: 'address',
  35. key: 'address 3',
  36. ellipsis: true,
  37. },
  38. {
  39. title: 'Long Column',
  40. dataIndex: 'address',
  41. key: 'address 4',
  42. ellipsis: true,
  43. },
  44. ];
  45. const data = [
  46. {
  47. key: '1',
  48. name: 'John Brown',
  49. age: 32,
  50. address: 'New York No. 1 Lake Park, New York No. 1 Lake Park',
  51. tags: ['nice', 'developer'],
  52. },
  53. {
  54. key: '2',
  55. name: 'Jim Green',
  56. age: 42,
  57. address: 'London No. 2 Lake Park, London No. 2 Lake Park',
  58. tags: ['loser'],
  59. },
  60. {
  61. key: '3',
  62. name: 'Joe Black',
  63. age: 32,
  64. address: 'Sidney No. 1 Lake Park, Sidney No. 1 Lake Park',
  65. tags: ['cool', 'teacher'],
  66. },
  67. ];
  68. export default {
  69. data() {
  70. return {
  71. data,
  72. columns,
  73. };
  74. },
  75. };
  76. </script>

Table表格 - 图3

远程加载数据

这个例子通过简单的 ajax 读取方式,演示了如何从服务端读取并展现数据,具有筛选、排序等功能以及页面 loading 效果。开发者可以自行接入其他数据处理方式。
另外,本例也展示了筛选排序功能如何交给服务端实现,列不需要指定具体的 onFiltersorter 函数,而是在把筛选和排序的参数发到服务端来处理。
注意,此示例使用 模拟接口,展示数据可能不准确,请打开网络面板查看请求。

  1. <template>
  2. <a-table
  3. :columns="columns"
  4. :row-key="record => record.login.uuid"
  5. :data-source="data"
  6. :pagination="pagination"
  7. :loading="loading"
  8. @change="handleTableChange"
  9. >
  10. <template slot="name" slot-scope="name"> {{ name.first }} {{ name.last }} </template>
  11. </a-table>
  12. </template>
  13. <script>
  14. import reqwest from 'reqwest';
  15. const columns = [
  16. {
  17. title: 'Name',
  18. dataIndex: 'name',
  19. sorter: true,
  20. width: '20%',
  21. scopedSlots: { customRender: 'name' },
  22. },
  23. {
  24. title: 'Gender',
  25. dataIndex: 'gender',
  26. filters: [
  27. { text: 'Male', value: 'male' },
  28. { text: 'Female', value: 'female' },
  29. ],
  30. width: '20%',
  31. },
  32. {
  33. title: 'Email',
  34. dataIndex: 'email',
  35. },
  36. ];
  37. export default {
  38. data() {
  39. return {
  40. data: [],
  41. pagination: {},
  42. loading: false,
  43. columns,
  44. };
  45. },
  46. mounted() {
  47. this.fetch();
  48. },
  49. methods: {
  50. handleTableChange(pagination, filters, sorter) {
  51. console.log(pagination);
  52. const pager = { ...this.pagination };
  53. pager.current = pagination.current;
  54. this.pagination = pager;
  55. this.fetch({
  56. results: pagination.pageSize,
  57. page: pagination.current,
  58. sortField: sorter.field,
  59. sortOrder: sorter.order,
  60. ...filters,
  61. });
  62. },
  63. fetch(params = {}) {
  64. console.log('params:', params);
  65. this.loading = true;
  66. reqwest({
  67. url: 'https://randomuser.me/api',
  68. method: 'get',
  69. data: {
  70. results: 10,
  71. ...params,
  72. },
  73. type: 'json',
  74. }).then(data => {
  75. const pagination = { ...this.pagination };
  76. // Read total count from server
  77. // pagination.total = data.totalCount;
  78. pagination.total = 200;
  79. this.loading = false;
  80. this.data = data.results;
  81. this.pagination = pagination;
  82. });
  83. },
  84. },
  85. };
  86. </script>

Table表格 - 图4

带边框

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

  1. <template>
  2. <a-table :columns="columns" :data-source="data" bordered>
  3. <template slot="name" slot-scope="text">
  4. <a>{{ text }}</a>
  5. </template>
  6. <template slot="title" slot-scope="currentPageData">
  7. Header
  8. </template>
  9. <template slot="footer" slot-scope="currentPageData">
  10. Footer
  11. </template>
  12. </a-table>
  13. </template>
  14. <script>
  15. const columns = [
  16. {
  17. title: 'Name',
  18. dataIndex: 'name',
  19. scopedSlots: { customRender: 'name' },
  20. },
  21. {
  22. title: 'Cash Assets',
  23. className: 'column-money',
  24. dataIndex: 'money',
  25. },
  26. {
  27. title: 'Address',
  28. dataIndex: 'address',
  29. },
  30. ];
  31. const data = [
  32. {
  33. key: '1',
  34. name: 'John Brown',
  35. money: '¥300,000.00',
  36. address: 'New York No. 1 Lake Park',
  37. },
  38. {
  39. key: '2',
  40. name: 'Jim Green',
  41. money: '¥1,256,000.00',
  42. address: 'London No. 1 Lake Park',
  43. },
  44. {
  45. key: '3',
  46. name: 'Joe Black',
  47. money: '¥120,000.00',
  48. address: 'Sidney No. 1 Lake Park',
  49. },
  50. ];
  51. export default {
  52. data() {
  53. return {
  54. data,
  55. columns,
  56. };
  57. },
  58. };
  59. </script>
  60. <style>
  61. th.column-money,
  62. td.column-money {
  63. text-align: right !important;
  64. }
  65. </style>

Table表格 - 图5

表格行/列合并

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

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

Table表格 - 图6

自定义筛选菜单

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

  1. <template>
  2. <a-table :data-source="data" :columns="columns">
  3. <div
  4. slot="filterDropdown"
  5. slot-scope="{ setSelectedKeys, selectedKeys, confirm, clearFilters, column }"
  6. style="padding: 8px"
  7. >
  8. <a-input
  9. v-ant-ref="c => (searchInput = c)"
  10. :placeholder="`Search ${column.dataIndex}`"
  11. :value="selectedKeys[0]"
  12. style="width: 188px; margin-bottom: 8px; display: block;"
  13. @change="e => setSelectedKeys(e.target.value ? [e.target.value] : [])"
  14. @pressEnter="() => handleSearch(selectedKeys, confirm, column.dataIndex)"
  15. />
  16. <a-button
  17. type="primary"
  18. icon="search"
  19. size="small"
  20. style="width: 90px; margin-right: 8px"
  21. @click="() => handleSearch(selectedKeys, confirm, column.dataIndex)"
  22. >
  23. Search
  24. </a-button>
  25. <a-button size="small" style="width: 90px" @click="() => handleReset(clearFilters)">
  26. Reset
  27. </a-button>
  28. </div>
  29. <a-icon
  30. slot="filterIcon"
  31. slot-scope="filtered"
  32. type="search"
  33. :style="{ color: filtered ? '#108ee9' : undefined }"
  34. />
  35. <template slot="customRender" slot-scope="text, record, index, column">
  36. <span v-if="searchText && searchedColumn === column.dataIndex">
  37. <template
  38. v-for="(fragment, i) in text
  39. .toString()
  40. .split(new RegExp(`(?<=${searchText})|(?=${searchText})`, 'i'))"
  41. >
  42. <mark
  43. v-if="fragment.toLowerCase() === searchText.toLowerCase()"
  44. :key="i"
  45. class="highlight"
  46. >{{ fragment }}</mark
  47. >
  48. <template v-else>{{ fragment }}</template>
  49. </template>
  50. </span>
  51. <template v-else>
  52. {{ text }}
  53. </template>
  54. </template>
  55. </a-table>
  56. </template>
  57. <script>
  58. const data = [
  59. {
  60. key: '1',
  61. name: 'John Brown',
  62. age: 32,
  63. address: 'New York No. 1 Lake Park',
  64. },
  65. {
  66. key: '2',
  67. name: 'Joe Black',
  68. age: 42,
  69. address: 'London No. 1 Lake Park',
  70. },
  71. {
  72. key: '3',
  73. name: 'Jim Green',
  74. age: 32,
  75. address: 'Sidney No. 1 Lake Park',
  76. },
  77. {
  78. key: '4',
  79. name: 'Jim Red',
  80. age: 32,
  81. address: 'London No. 2 Lake Park',
  82. },
  83. ];
  84. export default {
  85. data() {
  86. return {
  87. data,
  88. searchText: '',
  89. searchInput: null,
  90. searchedColumn: '',
  91. columns: [
  92. {
  93. title: 'Name',
  94. dataIndex: 'name',
  95. key: 'name',
  96. scopedSlots: {
  97. filterDropdown: 'filterDropdown',
  98. filterIcon: 'filterIcon',
  99. customRender: 'customRender',
  100. },
  101. onFilter: (value, record) =>
  102. record.name
  103. .toString()
  104. .toLowerCase()
  105. .includes(value.toLowerCase()),
  106. onFilterDropdownVisibleChange: visible => {
  107. if (visible) {
  108. setTimeout(() => {
  109. this.searchInput.focus();
  110. }, 0);
  111. }
  112. },
  113. },
  114. {
  115. title: 'Age',
  116. dataIndex: 'age',
  117. key: 'age',
  118. scopedSlots: {
  119. filterDropdown: 'filterDropdown',
  120. filterIcon: 'filterIcon',
  121. customRender: 'customRender',
  122. },
  123. onFilter: (value, record) =>
  124. record.age
  125. .toString()
  126. .toLowerCase()
  127. .includes(value.toLowerCase()),
  128. onFilterDropdownVisibleChange: visible => {
  129. if (visible) {
  130. setTimeout(() => {
  131. this.searchInput.focus();
  132. });
  133. }
  134. },
  135. },
  136. {
  137. title: 'Address',
  138. dataIndex: 'address',
  139. key: 'address',
  140. scopedSlots: {
  141. filterDropdown: 'filterDropdown',
  142. filterIcon: 'filterIcon',
  143. customRender: 'customRender',
  144. },
  145. onFilter: (value, record) =>
  146. record.address
  147. .toString()
  148. .toLowerCase()
  149. .includes(value.toLowerCase()),
  150. onFilterDropdownVisibleChange: visible => {
  151. if (visible) {
  152. setTimeout(() => {
  153. this.searchInput.focus();
  154. });
  155. }
  156. },
  157. },
  158. ],
  159. };
  160. },
  161. methods: {
  162. handleSearch(selectedKeys, confirm, dataIndex) {
  163. confirm();
  164. this.searchText = selectedKeys[0];
  165. this.searchedColumn = dataIndex;
  166. },
  167. handleReset(clearFilters) {
  168. clearFilters();
  169. this.searchText = '';
  170. },
  171. },
  172. };
  173. </script>
  174. <style scoped>
  175. .highlight {
  176. background-color: rgb(255, 192, 105);
  177. padding: 0px;
  178. }
  179. </style>

Table表格 - 图7

可编辑单元格

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

  1. <template>
  2. <div>
  3. <a-button class="editable-add-btn" @click="handleAdd">
  4. Add
  5. </a-button>
  6. <a-table bordered :data-source="dataSource" :columns="columns">
  7. <template slot="name" slot-scope="text, record">
  8. <editable-cell :text="text" @change="onCellChange(record.key, 'name', $event)" />
  9. </template>
  10. <template slot="operation" slot-scope="text, record">
  11. <a-popconfirm
  12. v-if="dataSource.length"
  13. title="Sure to delete?"
  14. @confirm="() => onDelete(record.key)"
  15. >
  16. <a href="javascript:;">Delete</a>
  17. </a-popconfirm>
  18. </template>
  19. </a-table>
  20. </div>
  21. </template>
  22. <script>
  23. const EditableCell = {
  24. template: `
  25. <div class="editable-cell">
  26. <div v-if="editable" class="editable-cell-input-wrapper">
  27. <a-input :value="value" @change="handleChange" @pressEnter="check" /><a-icon
  28. type="check"
  29. class="editable-cell-icon-check"
  30. @click="check"
  31. />
  32. </div>
  33. <div v-else class="editable-cell-text-wrapper">
  34. {{ value || ' ' }}
  35. <a-icon type="edit" class="editable-cell-icon" @click="edit" />
  36. </div>
  37. </div>
  38. `,
  39. props: {
  40. text: String,
  41. },
  42. data() {
  43. return {
  44. value: this.text,
  45. editable: false,
  46. };
  47. },
  48. methods: {
  49. handleChange(e) {
  50. const value = e.target.value;
  51. this.value = value;
  52. },
  53. check() {
  54. this.editable = false;
  55. this.$emit('change', this.value);
  56. },
  57. edit() {
  58. this.editable = true;
  59. },
  60. },
  61. };
  62. export default {
  63. components: {
  64. EditableCell,
  65. },
  66. data() {
  67. return {
  68. dataSource: [
  69. {
  70. key: '0',
  71. name: 'Edward King 0',
  72. age: '32',
  73. address: 'London, Park Lane no. 0',
  74. },
  75. {
  76. key: '1',
  77. name: 'Edward King 1',
  78. age: '32',
  79. address: 'London, Park Lane no. 1',
  80. },
  81. ],
  82. count: 2,
  83. columns: [
  84. {
  85. title: 'name',
  86. dataIndex: 'name',
  87. width: '30%',
  88. scopedSlots: { customRender: 'name' },
  89. },
  90. {
  91. title: 'age',
  92. dataIndex: 'age',
  93. },
  94. {
  95. title: 'address',
  96. dataIndex: 'address',
  97. },
  98. {
  99. title: 'operation',
  100. dataIndex: 'operation',
  101. scopedSlots: { customRender: 'operation' },
  102. },
  103. ],
  104. };
  105. },
  106. methods: {
  107. onCellChange(key, dataIndex, value) {
  108. const dataSource = [...this.dataSource];
  109. const target = dataSource.find(item => item.key === key);
  110. if (target) {
  111. target[dataIndex] = value;
  112. this.dataSource = dataSource;
  113. }
  114. },
  115. onDelete(key) {
  116. const dataSource = [...this.dataSource];
  117. this.dataSource = dataSource.filter(item => item.key !== key);
  118. },
  119. handleAdd() {
  120. const { count, dataSource } = this;
  121. const newData = {
  122. key: count,
  123. name: `Edward King ${count}`,
  124. age: 32,
  125. address: `London, Park Lane no. ${count}`,
  126. };
  127. this.dataSource = [...dataSource, newData];
  128. this.count = count + 1;
  129. },
  130. },
  131. };
  132. </script>
  133. <style>
  134. .editable-cell {
  135. position: relative;
  136. }
  137. .editable-cell-input-wrapper,
  138. .editable-cell-text-wrapper {
  139. padding-right: 24px;
  140. }
  141. .editable-cell-text-wrapper {
  142. padding: 5px 24px 5px 5px;
  143. }
  144. .editable-cell-icon,
  145. .editable-cell-icon-check {
  146. position: absolute;
  147. right: 0;
  148. width: 20px;
  149. cursor: pointer;
  150. }
  151. .editable-cell-icon {
  152. line-height: 18px;
  153. display: none;
  154. }
  155. .editable-cell-icon-check {
  156. line-height: 28px;
  157. }
  158. .editable-cell:hover .editable-cell-icon {
  159. display: inline-block;
  160. }
  161. .editable-cell-icon:hover,
  162. .editable-cell-icon-check:hover {
  163. color: #108ee9;
  164. }
  165. .editable-add-btn {
  166. margin-bottom: 8px;
  167. }
  168. </style>

Table表格 - 图8

可编辑行

带行编辑功能的表格。

  1. <template>
  2. <a-table :columns="columns" :data-source="data" bordered>
  3. <template
  4. v-for="col in ['name', 'age', 'address']"
  5. :slot="col"
  6. slot-scope="text, record, index"
  7. >
  8. <div :key="col">
  9. <a-input
  10. v-if="record.editable"
  11. style="margin: -5px 0"
  12. :value="text"
  13. @change="e => handleChange(e.target.value, record.key, col)"
  14. />
  15. <template v-else>
  16. {{ text }}
  17. </template>
  18. </div>
  19. </template>
  20. <template slot="operation" slot-scope="text, record, index">
  21. <div class="editable-row-operations">
  22. <span v-if="record.editable">
  23. <a @click="() => save(record.key)">Save</a>
  24. <a-popconfirm title="Sure to cancel?" @confirm="() => cancel(record.key)">
  25. <a>Cancel</a>
  26. </a-popconfirm>
  27. </span>
  28. <span v-else>
  29. <a :disabled="editingKey !== ''" @click="() => edit(record.key)">Edit</a>
  30. </span>
  31. </div>
  32. </template>
  33. </a-table>
  34. </template>
  35. <script>
  36. const columns = [
  37. {
  38. title: 'name',
  39. dataIndex: 'name',
  40. width: '25%',
  41. scopedSlots: { customRender: 'name' },
  42. },
  43. {
  44. title: 'age',
  45. dataIndex: 'age',
  46. width: '15%',
  47. scopedSlots: { customRender: 'age' },
  48. },
  49. {
  50. title: 'address',
  51. dataIndex: 'address',
  52. width: '40%',
  53. scopedSlots: { customRender: 'address' },
  54. },
  55. {
  56. title: 'operation',
  57. dataIndex: 'operation',
  58. scopedSlots: { customRender: 'operation' },
  59. },
  60. ];
  61. const data = [];
  62. for (let i = 0; i < 100; i++) {
  63. data.push({
  64. key: i.toString(),
  65. name: `Edrward ${i}`,
  66. age: 32,
  67. address: `London Park no. ${i}`,
  68. });
  69. }
  70. export default {
  71. data() {
  72. this.cacheData = data.map(item => ({ ...item }));
  73. return {
  74. data,
  75. columns,
  76. editingKey: '',
  77. };
  78. },
  79. methods: {
  80. handleChange(value, key, column) {
  81. const newData = [...this.data];
  82. const target = newData.filter(item => key === item.key)[0];
  83. if (target) {
  84. target[column] = value;
  85. this.data = newData;
  86. }
  87. },
  88. edit(key) {
  89. const newData = [...this.data];
  90. const target = newData.filter(item => key === item.key)[0];
  91. this.editingKey = key;
  92. if (target) {
  93. target.editable = true;
  94. this.data = newData;
  95. }
  96. },
  97. save(key) {
  98. const newData = [...this.data];
  99. const newCacheData = [...this.cacheData];
  100. const target = newData.filter(item => key === item.key)[0];
  101. const targetCache = newCacheData.filter(item => key === item.key)[0];
  102. if (target && targetCache) {
  103. delete target.editable;
  104. this.data = newData;
  105. Object.assign(targetCache, target);
  106. this.cacheData = newCacheData;
  107. }
  108. this.editingKey = '';
  109. },
  110. cancel(key) {
  111. const newData = [...this.data];
  112. const target = newData.filter(item => key === item.key)[0];
  113. this.editingKey = '';
  114. if (target) {
  115. Object.assign(target, this.cacheData.filter(item => key === item.key)[0]);
  116. delete target.editable;
  117. this.data = newData;
  118. }
  119. },
  120. },
  121. };
  122. </script>
  123. <style scoped>
  124. .editable-row-operations a {
  125. margin-right: 8px;
  126. }
  127. </style>

Table表格 - 图9

树形数据展示

表格支持树形数据的展示,当数据中有 children 字段时会自动展示为树形表格,如果不需要或配置为其他字段可以用 childrenColumnName 进行配置。
可以通过设置 indentSize 以控制每一层的缩进宽度。

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

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

Table表格 - 图10

可展开

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

  1. <template>
  2. <a-table :columns="columns" :data-source="data">
  3. <a slot="action" slot-scope="text" href="javascript:;">Delete</a>
  4. <p slot="expandedRowRender" slot-scope="record" style="margin: 0">
  5. {{ record.description }}
  6. </p>
  7. </a-table>
  8. </template>
  9. <script>
  10. const columns = [
  11. { title: 'Name', dataIndex: 'name', key: 'name' },
  12. { title: 'Age', dataIndex: 'age', key: 'age' },
  13. { title: 'Address', dataIndex: 'address', key: 'address' },
  14. { title: 'Action', dataIndex: '', key: 'x', scopedSlots: { customRender: 'action' } },
  15. ];
  16. const data = [
  17. {
  18. key: 1,
  19. name: 'John Brown',
  20. age: 32,
  21. address: 'New York No. 1 Lake Park',
  22. description: 'My name is John Brown, I am 32 years old, living in 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. description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.',
  30. },
  31. {
  32. key: 3,
  33. name: 'Joe Black',
  34. age: 32,
  35. address: 'Sidney No. 1 Lake Park',
  36. description: 'My name is Joe Black, I am 32 years old, living in Sidney No. 1 Lake Park.',
  37. },
  38. ];
  39. export default {
  40. data() {
  41. return {
  42. data,
  43. columns,
  44. };
  45. },
  46. };
  47. </script>

Table表格 - 图11

固定头和列

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

若列头与内容不对齐或出现列重复,请指定固定列的宽度 width。如果指定 width 不生效或出现白色垂直空隙,请尝试建议留一列不设宽度以适应弹性布局,或者检查是否有超长连续字段破坏布局。
建议指定 scroll.x 为大于表格宽度的固定值或百分比。注意,且非固定列宽度之和不要超过 scroll.x

  1. <template>
  2. <a-table :columns="columns" :data-source="data" :scroll="{ x: 1500, y: 300 }">
  3. <a slot="action" slot-scope="text">action</a>
  4. </a-table>
  5. </template>
  6. <script>
  7. const columns = [
  8. { title: 'Full Name', width: 100, dataIndex: 'name', key: 'name', fixed: 'left' },
  9. { title: 'Age', width: 100, dataIndex: 'age', key: 'age', fixed: 'left' },
  10. { title: 'Column 1', dataIndex: 'address', key: '1', width: 150 },
  11. { title: 'Column 2', dataIndex: 'address', key: '2', width: 150 },
  12. { title: 'Column 3', dataIndex: 'address', key: '3', width: 150 },
  13. { title: 'Column 4', dataIndex: 'address', key: '4', width: 150 },
  14. { title: 'Column 5', dataIndex: 'address', key: '5', width: 150 },
  15. { title: 'Column 6', dataIndex: 'address', key: '6', width: 150 },
  16. { title: 'Column 7', dataIndex: 'address', key: '7', width: 150 },
  17. { title: 'Column 8', dataIndex: 'address', key: '8' },
  18. {
  19. title: 'Action',
  20. key: 'operation',
  21. fixed: 'right',
  22. width: 100,
  23. scopedSlots: { customRender: 'action' },
  24. },
  25. ];
  26. const data = [];
  27. for (let i = 0; i < 100; i++) {
  28. data.push({
  29. key: i,
  30. name: `Edrward ${i}`,
  31. age: 32,
  32. address: `London Park no. ${i}`,
  33. });
  34. }
  35. export default {
  36. data() {
  37. return {
  38. data,
  39. columns,
  40. };
  41. },
  42. };
  43. </script>

Table表格 - 图12

固定列

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

若列头与内容不对齐或出现列重复,请指定固定列的宽度 width。如果指定 width 不生效或出现白色垂直空隙,请尝试建议留一列不设宽度以适应弹性布局,或者检查是否有超长连续字段破坏布局。
建议指定 scroll.x 为大于表格宽度的固定值或百分比。注意,且非固定列宽度之和不要超过 scroll.x

  1. <template>
  2. <a-table :columns="columns" :data-source="data" :scroll="{ x: 1300 }">
  3. <a slot="action" slot-scope="text" href="javascript:;">action</a>
  4. </a-table>
  5. </template>
  6. <script>
  7. const columns = [
  8. { title: 'Full Name', width: 100, dataIndex: 'name', key: 'name', fixed: 'left' },
  9. { title: 'Age', width: 100, dataIndex: 'age', key: 'age', fixed: 'left' },
  10. { title: 'Column 1', dataIndex: 'address', key: '1' },
  11. { title: 'Column 2', dataIndex: 'address', key: '2' },
  12. { title: 'Column 3', dataIndex: 'address', key: '3' },
  13. { title: 'Column 4', dataIndex: 'address', key: '4' },
  14. { title: 'Column 5', dataIndex: 'address', key: '5' },
  15. { title: 'Column 6', dataIndex: 'address', key: '6' },
  16. { title: 'Column 7', dataIndex: 'address', key: '7' },
  17. { title: 'Column 8', dataIndex: 'address', key: '8' },
  18. {
  19. title: 'Action',
  20. key: 'operation',
  21. fixed: 'right',
  22. width: 100,
  23. scopedSlots: { customRender: 'action' },
  24. },
  25. ];
  26. const data = [
  27. {
  28. key: '1',
  29. name: 'John Brown',
  30. age: 32,
  31. address: 'New York Park',
  32. },
  33. {
  34. key: '2',
  35. name: 'Jim Green',
  36. age: 40,
  37. address: 'London Park',
  38. },
  39. ];
  40. export default {
  41. data() {
  42. return {
  43. data,
  44. columns,
  45. };
  46. },
  47. };
  48. </script>

Table表格 - 图13

固定表头

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

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

  1. <template>
  2. <a-table
  3. :columns="columns"
  4. :data-source="data"
  5. :pagination="{ pageSize: 50 }"
  6. :scroll="{ y: 240 }"
  7. />
  8. </template>
  9. <script>
  10. const columns = [
  11. {
  12. title: 'Name',
  13. dataIndex: 'name',
  14. width: 150,
  15. },
  16. {
  17. title: 'Age',
  18. dataIndex: 'age',
  19. width: 150,
  20. },
  21. {
  22. title: 'Address',
  23. dataIndex: 'address',
  24. },
  25. ];
  26. const data = [];
  27. for (let i = 0; i < 100; i++) {
  28. data.push({
  29. key: i,
  30. name: `Edward King ${i}`,
  31. age: 32,
  32. address: `London, Park Lane no. ${i}`,
  33. });
  34. }
  35. export default {
  36. data() {
  37. return {
  38. data,
  39. columns,
  40. };
  41. },
  42. };
  43. </script>

Table表格 - 图14

表头分组

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

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

Table表格 - 图15

筛选和排序

对某一列数据进行筛选,使用列的 filters 属性来指定需要筛选菜单的列,onFilter 用于筛选当前数据,filterMultiple 用于指定多选和单选。
对某一列数据进行排序,通过指定列的 sorter 函数即可启动排序按钮。sorter: function(rowA, rowB) { ... }, rowA、rowB 为比较的两个行数据。
sortDirections: ['ascend' | 'descend']改变每列可用的排序方式,切换排序时按数组内容依次切换,设置在 table props 上时对所有列生效。
使用 defaultSortOrder 属性,设置列的默认排序顺序。

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

Table表格 - 图16

嵌套子表格

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

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

Table表格 - 图17

可控的筛选和排序

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

  1. columns 中定义了 filteredValue 和 sortOrder 属性即视为受控模式。
  2. 只支持同时对一列进行排序,请保证只有一列的 sortOrder 属性是生效的。
  3. 务必指定 column.key
  1. <template>
  2. <div>
  3. <div class="table-operations">
  4. <a-button @click="setAgeSort">
  5. Sort age
  6. </a-button>
  7. <a-button @click="clearFilters">
  8. Clear filters
  9. </a-button>
  10. <a-button @click="clearAll">
  11. Clear filters and sorters
  12. </a-button>
  13. </div>
  14. <a-table :columns="columns" :data-source="data" @change="handleChange" />
  15. </div>
  16. </template>
  17. <script>
  18. const data = [
  19. {
  20. key: '1',
  21. name: 'John Brown',
  22. age: 32,
  23. address: 'New York No. 1 Lake Park',
  24. },
  25. {
  26. key: '2',
  27. name: 'Jim Green',
  28. age: 42,
  29. address: 'London No. 1 Lake Park',
  30. },
  31. {
  32. key: '3',
  33. name: 'Joe Black',
  34. age: 32,
  35. address: 'Sidney No. 1 Lake Park',
  36. },
  37. {
  38. key: '4',
  39. name: 'Jim Red',
  40. age: 32,
  41. address: 'London No. 2 Lake Park',
  42. },
  43. ];
  44. export default {
  45. data() {
  46. return {
  47. data,
  48. filteredInfo: null,
  49. sortedInfo: null,
  50. };
  51. },
  52. computed: {
  53. columns() {
  54. let { sortedInfo, filteredInfo } = this;
  55. sortedInfo = sortedInfo || {};
  56. filteredInfo = filteredInfo || {};
  57. const columns = [
  58. {
  59. title: 'Name',
  60. dataIndex: 'name',
  61. key: 'name',
  62. filters: [
  63. { text: 'Joe', value: 'Joe' },
  64. { text: 'Jim', value: 'Jim' },
  65. ],
  66. filteredValue: filteredInfo.name || null,
  67. onFilter: (value, record) => record.name.includes(value),
  68. sorter: (a, b) => a.name.length - b.name.length,
  69. sortOrder: sortedInfo.columnKey === 'name' && sortedInfo.order,
  70. ellipsis: true,
  71. },
  72. {
  73. title: 'Age',
  74. dataIndex: 'age',
  75. key: 'age',
  76. sorter: (a, b) => a.age - b.age,
  77. sortOrder: sortedInfo.columnKey === 'age' && sortedInfo.order,
  78. },
  79. {
  80. title: 'Address',
  81. dataIndex: 'address',
  82. key: 'address',
  83. filters: [
  84. { text: 'London', value: 'London' },
  85. { text: 'New York', value: 'New York' },
  86. ],
  87. filteredValue: filteredInfo.address || null,
  88. onFilter: (value, record) => record.address.includes(value),
  89. sorter: (a, b) => a.address.length - b.address.length,
  90. sortOrder: sortedInfo.columnKey === 'address' && sortedInfo.order,
  91. ellipsis: true,
  92. },
  93. ];
  94. return columns;
  95. },
  96. },
  97. methods: {
  98. handleChange(pagination, filters, sorter) {
  99. console.log('Various parameters', pagination, filters, sorter);
  100. this.filteredInfo = filters;
  101. this.sortedInfo = sorter;
  102. },
  103. clearFilters() {
  104. this.filteredInfo = null;
  105. },
  106. clearAll() {
  107. this.filteredInfo = null;
  108. this.sortedInfo = null;
  109. },
  110. setAgeSort() {
  111. this.sortedInfo = {
  112. order: 'descend',
  113. columnKey: 'age',
  114. };
  115. },
  116. },
  117. };
  118. </script>
  119. <style scoped>
  120. .table-operations {
  121. margin-bottom: 16px;
  122. }
  123. .table-operations > button {
  124. margin-right: 8px;
  125. }
  126. </style>

Table表格 - 图18

选择和操作

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

  1. <template>
  2. <div>
  3. <div style="margin-bottom: 16px">
  4. <a-button type="primary" :disabled="!hasSelected" :loading="loading" @click="start">
  5. Reload
  6. </a-button>
  7. <span style="margin-left: 8px">
  8. <template v-if="hasSelected">
  9. {{ `Selected ${selectedRowKeys.length} items` }}
  10. </template>
  11. </span>
  12. </div>
  13. <a-table
  14. :row-selection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
  15. :columns="columns"
  16. :data-source="data"
  17. />
  18. </div>
  19. </template>
  20. <script>
  21. const columns = [
  22. {
  23. title: 'Name',
  24. dataIndex: 'name',
  25. },
  26. {
  27. title: 'Age',
  28. dataIndex: 'age',
  29. },
  30. {
  31. title: 'Address',
  32. dataIndex: 'address',
  33. },
  34. ];
  35. const data = [];
  36. for (let i = 0; i < 46; i++) {
  37. data.push({
  38. key: i,
  39. name: `Edward King ${i}`,
  40. age: 32,
  41. address: `London, Park Lane no. ${i}`,
  42. });
  43. }
  44. export default {
  45. data() {
  46. return {
  47. data,
  48. columns,
  49. selectedRowKeys: [], // Check here to configure the default column
  50. loading: false,
  51. };
  52. },
  53. computed: {
  54. hasSelected() {
  55. return this.selectedRowKeys.length > 0;
  56. },
  57. },
  58. methods: {
  59. start() {
  60. this.loading = true;
  61. // ajax request after empty completing
  62. setTimeout(() => {
  63. this.loading = false;
  64. this.selectedRowKeys = [];
  65. }, 1000);
  66. },
  67. onSelectChange(selectedRowKeys) {
  68. console.log('selectedRowKeys changed: ', selectedRowKeys);
  69. this.selectedRowKeys = selectedRowKeys;
  70. },
  71. },
  72. };
  73. </script>

Table表格 - 图19

自定义选择项

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

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

Table表格 - 图20

可选择

第一列是联动的选择框。

默认点击 checkbox 触发选择行为

  1. <template>
  2. <a-table :row-selection="rowSelection" :columns="columns" :data-source="data">
  3. <a slot="name" slot-scope="text">{{ text }}</a>
  4. </a-table>
  5. </template>
  6. <script>
  7. const columns = [
  8. {
  9. title: 'Name',
  10. dataIndex: 'name',
  11. scopedSlots: { customRender: 'name' },
  12. },
  13. {
  14. title: 'Age',
  15. dataIndex: 'age',
  16. },
  17. {
  18. title: 'Address',
  19. dataIndex: 'address',
  20. },
  21. ];
  22. const data = [
  23. {
  24. key: '1',
  25. name: 'John Brown',
  26. age: 32,
  27. address: 'New York No. 1 Lake Park',
  28. },
  29. {
  30. key: '2',
  31. name: 'Jim Green',
  32. age: 42,
  33. address: 'London No. 1 Lake Park',
  34. },
  35. {
  36. key: '3',
  37. name: 'Joe Black',
  38. age: 32,
  39. address: 'Sidney No. 1 Lake Park',
  40. },
  41. {
  42. key: '4',
  43. name: 'Disabled User',
  44. age: 99,
  45. address: 'Sidney No. 1 Lake Park',
  46. },
  47. ];
  48. export default {
  49. data() {
  50. return {
  51. data,
  52. columns,
  53. };
  54. },
  55. computed: {
  56. rowSelection() {
  57. return {
  58. onChange: (selectedRowKeys, selectedRows) => {
  59. console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
  60. },
  61. getCheckboxProps: record => ({
  62. props: {
  63. disabled: record.name === 'Disabled User', // Column configuration not to be checked
  64. name: record.name,
  65. },
  66. }),
  67. };
  68. },
  69. },
  70. };
  71. </script>

Table表格 - 图21

紧凑型

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

  1. <template>
  2. <div id="components-table-demo-size">
  3. <h4>Middle size table</h4>
  4. <a-table :columns="columns" :data-source="data" size="middle" />
  5. <h4>Small size table</h4>
  6. <a-table :columns="columns" :data-source="data" size="small" />
  7. </div>
  8. </template>
  9. <script>
  10. const columns = [
  11. {
  12. title: 'Name',
  13. dataIndex: 'name',
  14. },
  15. {
  16. title: 'Age',
  17. dataIndex: 'age',
  18. },
  19. {
  20. title: 'Address',
  21. dataIndex: 'address',
  22. },
  23. ];
  24. const data = [
  25. {
  26. key: '1',
  27. name: 'John Brown',
  28. age: 32,
  29. address: 'New York No. 1 Lake Park',
  30. },
  31. {
  32. key: '2',
  33. name: 'Jim Green',
  34. age: 42,
  35. address: 'London No. 1 Lake Park',
  36. },
  37. {
  38. key: '3',
  39. name: 'Joe Black',
  40. age: 32,
  41. address: 'Sidney No. 1 Lake Park',
  42. },
  43. ];
  44. export default {
  45. data() {
  46. return {
  47. data,
  48. columns,
  49. };
  50. },
  51. };
  52. </script>
  53. <style>
  54. #components-table-demo-size h4 {
  55. margin-bottom: 16px;
  56. }
  57. </style>

Table表格 - 图22

template 风格的 API

使用 template 风格的 API

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

  1. <template>
  2. <a-table :data-source="data">
  3. <a-table-column-group>
  4. <span slot="title" style="color: #1890ff">Name</span>
  5. <a-table-column key="firstName" data-index="firstName">
  6. <span slot="title" style="color: #1890ff">First Name</span>
  7. </a-table-column>
  8. <a-table-column key="lastName" title="Last Name" data-index="lastName" />
  9. </a-table-column-group>
  10. <a-table-column key="age" title="Age" data-index="age" />
  11. <a-table-column key="address" title="Address" data-index="address" />
  12. <a-table-column key="tags" title="Tags" data-index="tags">
  13. <template slot-scope="tags">
  14. <span>
  15. <a-tag v-for="tag in tags" :key="tag" color="blue">{{ tag }}</a-tag>
  16. </span>
  17. </template>
  18. </a-table-column>
  19. <a-table-column key="action" title="Action">
  20. <template slot-scope="text, record">
  21. <span>
  22. <a>Action 一 {{ record.firstName }}</a>
  23. <a-divider type="vertical" />
  24. <a>Delete</a>
  25. </span>
  26. </template>
  27. </a-table-column>
  28. </a-table>
  29. </template>
  30. <script>
  31. const data = [
  32. {
  33. key: '1',
  34. firstName: 'John',
  35. lastName: 'Brown',
  36. age: 32,
  37. address: 'New York No. 1 Lake Park',
  38. tags: ['nice', 'developer'],
  39. },
  40. {
  41. key: '2',
  42. firstName: 'Jim',
  43. lastName: 'Green',
  44. age: 42,
  45. address: 'London No. 1 Lake Park',
  46. tags: ['loser'],
  47. },
  48. {
  49. key: '3',
  50. firstName: 'Joe',
  51. lastName: 'Black',
  52. age: 32,
  53. address: 'Sidney No. 1 Lake Park',
  54. tags: ['cool', 'teacher'],
  55. },
  56. ];
  57. export default {
  58. data() {
  59. return {
  60. data,
  61. };
  62. },
  63. };
  64. </script>

Table表格 - 图23

可伸缩列

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

  1. <template>
  2. <a-table bordered :columns="columns" :components="components" :data-source="data">
  3. <template v-slot:action>
  4. <a href="javascript:;">Delete</a>
  5. </template>
  6. </a-table>
  7. </template>
  8. <script>
  9. import Vue from 'vue';
  10. import VueDraggableResizable from 'vue-draggable-resizable';
  11. Vue.component('vue-draggable-resizable', VueDraggableResizable);
  12. const columns = [
  13. {
  14. title: 'Date',
  15. dataIndex: 'date',
  16. width: 200,
  17. },
  18. {
  19. title: 'Amount',
  20. dataIndex: 'amount',
  21. width: 100,
  22. },
  23. {
  24. title: 'Type',
  25. dataIndex: 'type',
  26. width: 100,
  27. },
  28. {
  29. title: 'Note',
  30. dataIndex: 'note',
  31. width: 100,
  32. },
  33. {
  34. title: 'Action',
  35. key: 'action',
  36. scopedSlots: { customRender: 'action' },
  37. },
  38. ];
  39. const data = [
  40. {
  41. key: 0,
  42. date: '2018-02-11',
  43. amount: 120,
  44. type: 'income',
  45. note: 'transfer',
  46. },
  47. {
  48. key: 1,
  49. date: '2018-03-11',
  50. amount: 243,
  51. type: 'income',
  52. note: 'transfer',
  53. },
  54. {
  55. key: 2,
  56. date: '2018-04-11',
  57. amount: 98,
  58. type: 'income',
  59. note: 'transfer',
  60. },
  61. ];
  62. const draggingMap = {};
  63. columns.forEach(col => {
  64. draggingMap[col.key] = col.width;
  65. });
  66. const draggingState = Vue.observable(draggingMap);
  67. const ResizeableTitle = (h, props, children) => {
  68. let thDom = null;
  69. const { key, ...restProps } = props;
  70. const col = columns.find(col => {
  71. const k = col.dataIndex || col.key;
  72. return k === key;
  73. });
  74. if (!col.width) {
  75. return <th {...restProps}>{children}</th>;
  76. }
  77. const onDrag = x => {
  78. draggingState[key] = 0;
  79. col.width = Math.max(x, 1);
  80. };
  81. const onDragstop = () => {
  82. draggingState[key] = thDom.getBoundingClientRect().width;
  83. };
  84. return (
  85. <th {...restProps} v-ant-ref={r => (thDom = r)} width={col.width} class="resize-table-th">
  86. {children}
  87. <vue-draggable-resizable
  88. key={col.key}
  89. class="table-draggable-handle"
  90. w={10}
  91. x={draggingState[key] || col.width}
  92. z={1}
  93. axis="x"
  94. draggable={true}
  95. resizable={false}
  96. onDragging={onDrag}
  97. onDragstop={onDragstop}
  98. ></vue-draggable-resizable>
  99. </th>
  100. );
  101. };
  102. export default {
  103. name: 'App',
  104. data() {
  105. this.components = {
  106. header: {
  107. cell: ResizeableTitle,
  108. },
  109. };
  110. return {
  111. data,
  112. columns,
  113. };
  114. },
  115. };
  116. </script>
  117. <style lang="less">
  118. .resize-table-th {
  119. position: relative;
  120. .table-draggable-handle {
  121. height: 100% !important;
  122. bottom: 0;
  123. left: auto !important;
  124. right: -5px;
  125. cursor: col-resize;
  126. touch-action: none;
  127. }
  128. }
  129. </style>

API

Table

参数说明类型默认值版本
tableLayout表格元素的 table-layout 属性,设为 fixed 表示内容不会影响列的布局- | ‘auto’ | ‘fixed’
固定表头/列或使用了 column.ellipsis 时,默认值为 fixed
1.5.0
bordered是否展示外边框和列边框booleanfalse
childrenColumnName指定树形结构的列名string[]children
columns表格列的配置描述,具体项见下表array-
components覆盖默认的 table 元素object-
dataSource数据数组any[]
defaultExpandAllRows初始时,是否展开所有行booleanfalse
defaultExpandedRowKeys默认展开的行string[]-
expandedRowKeys展开的行,控制属性string[]-
expandedRowRender额外的展开行Function(record, index, indent, expanded):VNode | slot=”expandedRowRender” slot-scope=”record, index, indent, expanded”-
expandIcon自定义展开图标Function(props):VNode | slot=”expandIcon” slot-scope=”props”-
expandRowByClick通过点击行来展开子行booleanfalse
expandIconColumnIndex展开的图标显示在哪一列,如果没有 rowSelection,默认显示在第一列,否则显示在选择框后面number
footer表格尾部Function(currentPageData)|slot-scope
indentSize展示树形数据时,每层缩进的宽度,以 px 为单位number15
loading页面是否加载中boolean|objectfalse
locale默认文案设置,目前包括排序、过滤、空数据文案objectfilterConfirm: ‘确定’
filterReset: ‘重置’
emptyText: ‘暂无数据’

pagination分页器,参考配置项pagination文档,设为 false 时不展示和进行分页object
rowClassName表格行的类名Function(record, index):string-
rowKey表格行 key 的取值,可以是字符串或一个函数string|Function(record):string‘key’
rowSelection列表项是否可选择,配置项objectnull
scroll设置横向或纵向滚动,也可用于指定滚动区域的宽和高,建议为 x 设置一个数字,如果要设置为 true,需要配合样式 .ant-table td { white-space: nowrap; }{ x: number | true, y: number }-
showHeader是否显示表头booleantrue
size表格大小default | middle | smalldefault
title表格标题Function(currentPageData)|slot-scope
customHeaderRow设置头部行属性Function(column, index)-
customRow设置行属性Function(record, index)-
getPopupContainer设置表格内各类浮层的渲染节点,如筛选菜单(triggerNode) => HTMLElement() => TableHtmlElement1.5.0
transformCellText数据渲染前可以再次改变,一般用户空数据的默认配置,可以通过 ConfigProvider 全局统一配置Function({ text, column, record, index }) => any-1.5.4

事件

事件名称说明回调参数
expandedRowsChange展开的行变化时触发Function(expandedRows)
change分页、排序、筛选变化时触发Function(pagination, filters, sorter, { currentDataSource })
expand点击展开图标时触发Function(expanded, record)

customRow 用法

适用于 customRow customHeaderRow customCell customHeaderCell。遵循Vue jsx语法。

  1. <Table
  2. customRow={(record) => {
  3. return {
  4. props: {
  5. xxx... //属性
  6. },
  7. on: { // 事件
  8. click: (event) => {}, // 点击行
  9. dblclick: (event) => {},
  10. contextmenu: (event) => {},
  11. mouseenter: (event) => {}, // 鼠标移入行
  12. mouseleave: (event) => {}
  13. },
  14. };
  15. )}
  16. customHeaderRow={(column) => {
  17. return {
  18. on: {
  19. click: () => {}, // 点击表头行
  20. }
  21. };
  22. )}
  23. />

Column

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

参数说明类型默认值版本
align设置列内容的对齐方式‘left’ | ‘right’ | ‘center’‘left’
ellipsis超过宽度将自动省略,暂不支持和排序筛选一起使用。
设置为 true 时,表格布局将变成 tableLayout=”fixed”
booleanfalse1.5.0
colSpan表头列合并,设置为 0 时,不渲染number
dataIndex列数据在数据项中对应的 key,支持 a.b.c 的嵌套写法string-
defaultFilteredValue默认筛选值string[]-1.5.0
filterDropdown可以自定义筛选菜单,此函数只负责渲染图层,需要自行编写各种交互VNode | slot-scope-
filterDropdownVisible用于控制自定义筛选菜单是否可见boolean-
filtered标识数据是否经过过滤,筛选图标会高亮booleanfalse
filteredValue筛选的受控属性,外界可用此控制列的筛选状态,值为已筛选的 value 数组string[]-
filterIcon自定义 fiter 图标。VNode | (filtered: boolean, column: Column) => vNode |slot |slot-scopefalse
filterMultiple是否多选booleantrue
filters表头的筛选菜单项object[]-
fixed列是否固定,可选 true(等效于 left) ‘left’ ‘right’boolean|stringfalse
keyVue 需要的 key,如果已经设置了唯一的 dataIndex,可以忽略这个属性string-
customRender生成复杂数据的渲染函数,参数分别为当前行的值,当前行数据,行索引,@return 里面可以设置表格行/列合并,可参考 demo 表格行/列合并Function(text, record, index) {}|slot-scope-
sorter排序函数,本地排序使用一个函数(参考 Array.sort 的 compareFunction),需要服务端排序可设为 trueFunction|boolean-
sortOrder排序的受控属性,外界可用此控制列的排序,可设置为 ‘ascend’ ‘descend’ falseboolean|string-
sortDirections支持的排序方式,取值为 ‘ascend’ ‘descend’Array[‘ascend’, ‘descend’]1.5.0
title列头显示文字string|slot-
width列宽度string|number-
customCell设置单元格属性Function(record, rowIndex)-
customHeaderCell设置头部单元格属性Function(column)-
onFilter本地模式下,确定筛选的运行函数, 使用 template 或 jsx 时作为filter事件使用Function-
onFilterDropdownVisibleChange自定义筛选菜单可见变化时调用,使用 template 或 jsx 时作为filterDropdownVisibleChange事件使用function(visible) {}-
slots使用 columns 时,可以通过该属性配置支持 slot 的属性,如 slots: { filterIcon: ‘XXX’}object-
scopedSlots使用 columns 时,可以通过该属性配置支持 slot-scope 的属性,如 scopedSlots: { customRender: ‘XXX’}object-

ColumnGroup

参数说明类型默认值
title列头显示文字string|slot-
slots使用 columns 时,可以通过该属性配置支持 slot 的属性,如 slots: { title: ‘XXX’}object-

pagination

分页的配置项。

参数说明类型默认值
position指定分页显示的位置‘top’ | ‘bottom’ | ‘both’‘bottom’

更多配置项,请查看 Pagination

rowSelection

选择功能的配置。

参数说明类型默认值
columnWidth自定义列表选择框宽度string|number-
columnTitle自定义列表选择框标题string|VNode-
fixed把选择框列固定在左边boolean-
getCheckboxProps选择框的默认属性配置Function(record)-
hideDefaultSelections去掉『全选』『反选』两个默认选项booleanfalse
selectedRowKeys指定选中项的 key 数组,需要和 onChange 进行配合string[][]
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-1.5.0

selection

自定义选择配置项

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

注意

在 Table 中,dataSourcecolumns 里的数据值都需要指定 key 值。对于 dataSource 默认将每列数据的 key 属性作为唯一的标识。

如果你的数据没有这个属性,务必使用 rowKey 来指定数据列的主键。若没有指定,控制台会出现缺少 key 的提示,表格组件也会出现各类奇怪的错误。

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