- Table 表格
- 何时使用
- 如何使用
- 代码演示
- 远程加载数据
- 基本用法
- 带边框
- 表格行/列合并
- 自定义筛选菜单
- 可编辑单元格
- 可编辑行
- 树形数据展示
- 可展开
- 固定头和列
- 固定列
- 固定表头
- 表头分组
- 筛选和排序
- 嵌套子表格
- 可控的筛选和排序
- 选择和操作
- 自定义选择项
- 可选择
- 紧凑型
- template 风格的 API
- API
- Table
- 事件
- customRow 用法
- Column
- ColumnGroup
- pagination
- rowSelection
- selection
- 注意
Table 表格
展示行列数据。
何时使用
- 当有大量结构化的数据需要展现时;
- 当需要对数据进行排序、搜索、分页、自定义操作等复杂行为时。
如何使用
指定表格的数据源 dataSource 为一个数组。
代码演示

远程加载数据
这个例子通过简单的 ajax 读取方式,演示了如何从服务端读取并展现数据,具有筛选、排序等功能以及页面 loading 效果。开发者可以自行接入其他数据处理方式。另外,本例也展示了筛选排序功能如何交给服务端实现,列不需要指定具体的 onFilter 和 sorter 函数,而是在把筛选和排序的参数发到服务端来处理。注意,此示例使用 模拟接口,展示数据可能不准确,请打开网络面板查看请求。
<template><a-table:columns="columns":rowKey="record => record.login.uuid":dataSource="data":pagination="pagination":loading="loading"@change="handleTableChange"><template slot="name" slot-scope="name">{{name.first}} {{name.last}}</template></a-table></template><script>import reqwest from 'reqwest';const columns = [{title: 'Name',dataIndex: 'name',sorter: true,width: '20%',scopedSlots: { customRender: 'name' },},{title: 'Gender',dataIndex: 'gender',filters: [{ text: 'Male', value: 'male' }, { text: 'Female', value: 'female' }],width: '20%',},{title: 'Email',dataIndex: 'email',},];export default {mounted() {this.fetch();},data() {return {data: [],pagination: {},loading: false,columns,};},methods: {handleTableChange(pagination, filters, sorter) {console.log(pagination);const pager = { ...this.pagination };pager.current = pagination.current;this.pagination = pager;this.fetch({results: pagination.pageSize,page: pagination.current,sortField: sorter.field,sortOrder: sorter.order,...filters,});},fetch(params = {}) {console.log('params:', params);this.loading = true;reqwest({url: 'https://randomuser.me/api',method: 'get',data: {results: 10,...params,},type: 'json',}).then(data => {const pagination = { ...this.pagination };// Read total count from server// pagination.total = data.totalCount;pagination.total = 200;this.loading = false;this.data = data.results;this.pagination = pagination;});},},};</script>

基本用法
简单的表格,最后一列是各种操作。
<template><a-table :columns="columns" :dataSource="data"><a slot="name" slot-scope="text" href="javascript:;">{{text}}</a><span slot="customTitle"><a-icon type="smile-o" /> Name</span><span slot="tags" slot-scope="tags"><a-tagv-for="tag in tags":color="tag==='loser' ? 'volcano' : (tag.length > 5 ? 'geekblue' : 'green')":key="tag">{{tag.toUpperCase()}}</a-tag></span><span slot="action" slot-scope="text, record"><a href="javascript:;">Invite 一 {{record.name}}</a><a-divider type="vertical" /><a href="javascript:;">Delete</a><a-divider type="vertical" /><a href="javascript:;" class="ant-dropdown-link"> More actions <a-icon type="down" /> </a></span></a-table></template><script>const columns = [{dataIndex: 'name',key: 'name',slots: { title: 'customTitle' },scopedSlots: { customRender: 'name' },},{title: 'Age',dataIndex: 'age',key: 'age',},{title: 'Address',dataIndex: 'address',key: 'address',},{title: 'Tags',key: 'tags',dataIndex: 'tags',scopedSlots: { customRender: 'tags' },},{title: 'Action',key: 'action',scopedSlots: { customRender: 'action' },},];const data = [{key: '1',name: 'John Brown',age: 32,address: 'New York No. 1 Lake Park',tags: ['nice', 'developer'],},{key: '2',name: 'Jim Green',age: 42,address: 'London No. 1 Lake Park',tags: ['loser'],},{key: '3',name: 'Joe Black',age: 32,address: 'Sidney No. 1 Lake Park',tags: ['cool', 'teacher'],},];export default {data() {return {data,columns,};},};</script>

带边框
添加表格边框线,页头和页脚。
<template>
<a-table :columns="columns" :dataSource="data" bordered>
<template slot="name" slot-scope="text">
<a href="javascript:;">{{text}}</a>
</template>
<template slot="title" slot-scope="currentPageData">
Header
</template>
<template slot="footer" slot-scope="currentPageData">
Footer
</template>
</a-table>
</template>
<script>
const columns = [
{
title: 'Name',
dataIndex: 'name',
scopedSlots: { customRender: 'name' },
},
{
title: 'Cash Assets',
className: 'column-money',
dataIndex: 'money',
},
{
title: 'Address',
dataIndex: 'address',
},
];
const data = [
{
key: '1',
name: 'John Brown',
money: '¥300,000.00',
address: 'New York No. 1 Lake Park',
},
{
key: '2',
name: 'Jim Green',
money: '¥1,256,000.00',
address: 'London No. 1 Lake Park',
},
{
key: '3',
name: 'Joe Black',
money: '¥120,000.00',
address: 'Sidney No. 1 Lake Park',
},
];
export default {
data() {
return {
data,
columns,
};
},
};
</script>
<style>
th.column-money,
td.column-money {
text-align: right !important;
}
</style>

表格行/列合并
表头只支持列合并,使用 column 里的 colSpan 进行设置。表格支持行/列合并,使用 render 里的单元格属性 colSpan 或者 rowSpan 设值为 0 时,设置的表格不会渲染。
<template>
<a-table :columns="columns" :dataSource="data" bordered>
<template slot="name" slot-scope="text">
<a href="javascript:;">{{text}}</a>
</template>
</a-table>
</template>
<script>
// In the fifth row, other columns are merged into first column
// by setting it's colSpan to be 0
const renderContent = (value, row, index) => {
const obj = {
children: value,
attrs: {},
};
if (index === 4) {
obj.attrs.colSpan = 0;
}
return obj;
};
const data = [
{
key: '1',
name: 'John Brown',
age: 32,
tel: '0571-22098909',
phone: 18889898989,
address: 'New York No. 1 Lake Park',
},
{
key: '2',
name: 'Jim Green',
tel: '0571-22098333',
phone: 18889898888,
age: 42,
address: 'London No. 1 Lake Park',
},
{
key: '3',
name: 'Joe Black',
age: 32,
tel: '0575-22098909',
phone: 18900010002,
address: 'Sidney No. 1 Lake Park',
},
{
key: '4',
name: 'Jim Red',
age: 18,
tel: '0575-22098909',
phone: 18900010002,
address: 'London No. 2 Lake Park',
},
{
key: '5',
name: 'Jake White',
age: 18,
tel: '0575-22098909',
phone: 18900010002,
address: 'Dublin No. 2 Lake Park',
},
];
export default {
data() {
const columns = [
{
title: 'Name',
dataIndex: 'name',
customRender: (text, row, index) => {
if (index < 4) {
return <a href="javascript:;">{text}</a>;
}
return {
children: <a href="javascript:;">{text}</a>,
attrs: {
colSpan: 5,
},
};
},
},
{
title: 'Age',
dataIndex: 'age',
customRender: renderContent,
},
{
title: 'Home phone',
colSpan: 2,
dataIndex: 'tel',
customRender: (value, row, index) => {
const obj = {
children: value,
attrs: {},
};
if (index === 2) {
obj.attrs.rowSpan = 2;
}
// These two are merged into above cell
if (index === 3) {
obj.attrs.rowSpan = 0;
}
if (index === 4) {
obj.attrs.colSpan = 0;
}
return obj;
},
},
{
title: 'Phone',
colSpan: 0,
dataIndex: 'phone',
customRender: renderContent,
},
{
title: 'Address',
dataIndex: 'address',
customRender: renderContent,
},
];
return {
data,
columns,
};
},
};
</script>

自定义筛选菜单
通过 filterDropdown 定义自定义的列筛选功能,并实现一个搜索列的示例。
<template>
<a-table :dataSource="data" :columns="columns">
<div
slot="filterDropdown"
slot-scope="{ setSelectedKeys, selectedKeys, confirm, clearFilters, column }"
style="padding: 8px"
>
<a-input
v-ant-ref="c => searchInput = c"
:placeholder="`Search ${column.dataIndex}`"
:value="selectedKeys[0]"
@change="e => setSelectedKeys(e.target.value ? [e.target.value] : [])"
@pressEnter="() => handleSearch(selectedKeys, confirm)"
style="width: 188px; margin-bottom: 8px; display: block;"
/>
<a-button
type="primary"
@click="() => handleSearch(selectedKeys, confirm)"
icon="search"
size="small"
style="width: 90px; margin-right: 8px"
>Search</a-button
>
<a-button @click="() => handleReset(clearFilters)" size="small" style="width: 90px"
>Reset</a-button
>
</div>
<a-icon
slot="filterIcon"
slot-scope="filtered"
type="search"
:style="{ color: filtered ? '#108ee9' : undefined }"
/>
<template slot="customRender" slot-scope="text">
<span v-if="searchText">
<template
v-for="(fragment, i) in text.toString().split(new RegExp(`(?<=${searchText})|(?=${searchText})`, 'i'))"
>
<mark
v-if="fragment.toLowerCase() === searchText.toLowerCase()"
:key="i"
class="highlight"
>{{fragment}}</mark
>
<template v-else
>{{fragment}}</template
>
</template>
</span>
<template v-else
>{{text}}</template
>
</template>
</a-table>
</template>
<script>
const data = [
{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
},
{
key: '2',
name: 'Joe Black',
age: 42,
address: 'London No. 1 Lake Park',
},
{
key: '3',
name: 'Jim Green',
age: 32,
address: 'Sidney No. 1 Lake Park',
},
{
key: '4',
name: 'Jim Red',
age: 32,
address: 'London No. 2 Lake Park',
},
];
export default {
data() {
return {
data,
searchText: '',
searchInput: null,
columns: [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
scopedSlots: {
filterDropdown: 'filterDropdown',
filterIcon: 'filterIcon',
customRender: 'customRender',
},
onFilter: (value, record) => record.name.toString().toLowerCase().includes(value.toLowerCase()),
onFilterDropdownVisibleChange: visible => {
if (visible) {
setTimeout(() => {
this.searchInput.focus();
}, 0);
}
},
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
scopedSlots: {
filterDropdown: 'filterDropdown',
filterIcon: 'filterIcon',
customRender: 'customRender',
},
onFilter: (value, record) => record.age.toString().toLowerCase().includes(value.toLowerCase()),
onFilterDropdownVisibleChange: visible => {
if (visible) {
setTimeout(() => {
this.searchInput.focus();
});
}
},
},
{
title: 'Address',
dataIndex: 'address',
key: 'address',
scopedSlots: {
filterDropdown: 'filterDropdown',
filterIcon: 'filterIcon',
customRender: 'customRender',
},
onFilter: (value, record) => record.address.toString().toLowerCase().includes(value.toLowerCase()),
onFilterDropdownVisibleChange: visible => {
if (visible) {
setTimeout(() => {
this.searchInput.focus();
});
}
},
},
],
};
},
methods: {
handleSearch(selectedKeys, confirm) {
confirm();
this.searchText = selectedKeys[0];
},
handleReset(clearFilters) {
clearFilters();
this.searchText = '';
},
},
};
</script>
<style scoped>
.highlight {
background-color: rgb(255, 192, 105);
padding: 0px;
}
</