Antd Vue 组件库之Table表单
Table 表格
展示行列数据。
何时使用
- 当有大量结构化的数据需要展现时;
- 当需要对数据进行排序、搜索、分页、自定义操作等复杂行为时。
如何使用
指定表格的数据源 dataSource
为一个数组。
代码演示
Name
| Gender | |
---|---|---|
Candelária Cardoso | female | candelaria.cardoso@example.com |
Sienna Wood | female | sienna.wood@example.com |
Donna Thompson | female | donna.thompson@example.com |
Ron Edwards | male | ron.edwards@example.com |
Nuno Carpentier | male | nuno.carpentier@example.com |
Dorina Gröger | female | dorina.groger@example.com |
Mattia Rousseau | male | mattia.rousseau@example.com |
Éveline Fournier | female | eveline.fournier@example.com |
Luis Gonzales | male | luis.gonzales@example.com |
Annabelle Barnaby | female | annabelle.barnaby@example.com |
远程加载数据 #
这个例子通过简单的 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>
Name | Age | Address | Tags | Action |
---|---|---|---|---|
John Brown | 32 | New York No. 1 Lake Park | NICE DEVELOPER | Invite 一 John Brown Delete More actions |
Jim Green | 42 | London No. 1 Lake Park | LOSER | Invite 一 Jim Green Delete More actions |
Joe Black | 32 | Sidney No. 1 Lake Park | COOL TEACHER | Invite 一 Joe Black Delete More actions |
基本用法 #
简单的表格,最后一列是各种操作。
<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-tag
v-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>
Header
Name | Cash Assets | Address |
---|---|---|
John Brown | ¥300,000.00 | New York No. 1 Lake Park |
Jim Green | ¥1,256,000.00 | London No. 1 Lake Park |
Joe Black | ¥120,000.00 | Sidney No. 1 Lake Park |
Footer
带边框 #
添加表格边框线,页头和页脚。
<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>
Name | Age | Home phone | Address | |
---|---|---|---|---|
John Brown | 32 | 0571-22098909 | 18889898989 | New York No. 1 Lake Park |
Jim Green | 42 | 0571-22098333 | 18889898888 | London No. 1 Lake Park |
Joe Black | 32 | 0575-22098909 | 18900010002 | Sidney No. 1 Lake Park |
Jim Red | 18 | 18900010002 | London No. 2 Lake Park | |
Jake White |
表格行/列合并 #
表头只支持列合并,使用 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>
Name | Age | Address |
---|---|---|
John Brown | 32 | New York No. 1 Lake Park |
Joe Black | 42 | London No. 1 Lake Park |
Jim Green | 32 | Sidney No. 1 Lake Park |
Jim Red | 32 | London No. 2 Lake Park |
自定义筛选菜单 #
通过 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;
}
</style>
可编辑单元格 #
带单元格编辑功能的表格。
<template>
<div>
<a-button class="editable-add-btn" @click="handleAdd">Add</a-button>
<a-table bordered :dataSource="dataSource" :columns="columns">
<template slot="name" slot-scope="text, record">
<editable-cell :text="text" @change="onCellChange(record.key, 'name', $event)" />
</template>
<template slot="operation" slot-scope="text, record">
<a-popconfirm
v-if="dataSource.length"
title="Sure to delete?"
@confirm="() => onDelete(record.key)"
>
<a href="javascript:;">Delete</a>
</a-popconfirm>
</template>
</a-table>
</div>
</template>
<script>
import EditableCell from './EditableCell';
/*
* EditableCell Code https://github.com/vueComponent/ant-design-vue/blob/master/components/table/demo/EditableCell.vue
*/
export default {
components: {
EditableCell,
},
data() {
return {
dataSource: [
{
key: '0',
name: 'Edward King 0',
age: '32',
address: 'London, Park Lane no. 0',
},
{
key: '1',
name: 'Edward King 1',
age: '32',
address: 'London, Park Lane no. 1',
},
],
count: 2,
columns: [
{
title: 'name',
dataIndex: 'name',
width: '30%',
scopedSlots: { customRender: 'name' },
},
{
title: 'age',
dataIndex: 'age',
},
{
title: 'address',
dataIndex: 'address',
},
{
title: 'operation',
dataIndex: 'operation',
scopedSlots: { customRender: 'operation' },
},
],
};
},
methods: {
onCellChange(key, dataIndex, value) {
const dataSource = [...this.dataSource];
const target = dataSource.find(item => item.key === key);
if (target) {
target[dataIndex] = value;
this.dataSource = dataSource;
}
},
onDelete(key) {
const dataSource = [...this.dataSource];
this.dataSource = dataSource.filter(item => item.key !== key);
},
handleAdd() {
const { count, dataSource } = this;
const newData = {
key: count,
name: `Edward King ${count}`,
age: 32,
address: `London, Park Lane no. ${count}`,
};
this.dataSource = [...dataSource, newData];
this.count = count + 1;
},
},
};
</script>
<style>
.editable-cell {
position: relative;
}
.editable-cell-input-wrapper,
.editable-cell-text-wrapper {
padding-right: 24px;
}
.editable-cell-text-wrapper {
padding: 5px 24px 5px 5px;
}
.editable-cell-icon,
.editable-cell-icon-check {
position: absolute;
right: 0;
width: 20px;
cursor: pointer;
}
.editable-cell-icon {
line-height: 18px;
display: none;
}
.editable-cell-icon-check {
line-height: 28px;
}
.editable-cell:hover .editable-cell-icon {
display: inline-block;
}
.editable-cell-icon:hover,
.editable-cell-icon-check:hover {
color: #108ee9;
}
.editable-add-btn {
margin-bottom: 8px;
}
</style>
name | age | address | operation |
---|---|---|---|
Edrward 0 | 32 | London Park no. 0 | Edit |
Edrward 1 | 32 | London Park no. 1 | Edit |
Edrward 2 | 32 | London Park no. 2 | Edit |
Edrward 3 | 32 | London Park no. 3 | Edit |
Edrward 4 | 32 | London Park no. 4 | Edit |
Edrward 5 | 32 | London Park no. 5 | Edit |
Edrward 6 | 32 | London Park no. 6 | Edit |
Edrward 7 | 32 | London Park no. 7 | Edit |
Edrward 8 | 32 | London Park no. 8 | Edit |
Edrward 9 | 32 | London Park no. 9 | Edit |
可编辑行 #
带行编辑功能的表格。
<template>
<a-table :columns="columns" :dataSource="data" bordered>
<template
v-for="col in ['name', 'age', 'address']"
:slot="col"
slot-scope="text, record, index"
>
<div :key="col">
<a-input
v-if="record.editable"
style="margin: -5px 0"
:value="text"
@change="e => handleChange(e.target.value, record.key, col)"
/>
<template v-else
>{{text}}</template
>
</div>
</template>
<template slot="operation" slot-scope="text, record, index">
<div class="editable-row-operations">
<span v-if="record.editable">
<a @click="() => save(record.key)">Save</a>
<a-popconfirm title="Sure to cancel?" @confirm="() => cancel(record.key)">
<a>Cancel</a>
</a-popconfirm>
</span>
<span v-else>
<a @click="() => edit(record.key)">Edit</a>
</span>
</div>
</template>
</a-table>
</template>
<script>
const columns = [
{
title: 'name',
dataIndex: 'name',
width: '25%',
scopedSlots: { customRender: 'name' },
},
{
title: 'age',
dataIndex: 'age',
width: '15%',
scopedSlots: { customRender: 'age' },
},
{
title: 'address',
dataIndex: 'address',
width: '40%',
scopedSlots: { customRender: 'address' },
},
{
title: 'operation',
dataIndex: 'operation',
scopedSlots: { customRender: 'operation' },
},
];
const data = [];
for (let i = 0; i < 100; i++) {
data.push({
key: i.toString(),
name: `Edrward ${i}`,
age: 32,
address: `London Park no. ${i}`,
});
}
export default {
data() {
this.cacheData = data.map(item => ({ ...item }));
return {
data,
columns,
};
},
methods: {
handleChange(value, key, column) {
const newData = [...this.data];
const target = newData.filter(item => key === item.key)[0];
if (target) {
target[column] = value;
this.data = newData;
}
},
edit(key) {
const newData = [...this.data];
const target = newData.filter(item => key === item.key)[0];
if (target) {
target.editable = true;
this.data = newData;
}
},
save(key) {
const newData = [...this.data];
const target = newData.filter(item => key === item.key)[0];
if (target) {
delete target.editable;
this.data = newData;
this.cacheData = newData.map(item => ({ ...item }));
}
},
cancel(key) {
const newData = [...this.data];
const target = newData.filter(item => key === item.key)[0];
if (target) {
Object.assign(target, this.cacheData.filter(item => key === item.key)[0]);
delete target.editable;
this.data = newData;
}
},
},
};
</script>
<style scoped>
.editable-row-operations a {
margin-right: 8px;
}
</style>
树形数据展示 #
表格支持树形数据的展示,当数据中有 children
字段时会自动展示为树形表格,如果不需要或配置为其他字段可以用 childrenColumnName
进行配置。
可以通过设置 indentSize
以控制每一层的缩进宽度。
注:暂不支持父子数据递归关联选择。
<template>
<a-table :columns="columns" :dataSource="data" :rowSelection="rowSelection" />
</template>
<script>
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
width: '12%',
},
{
title: 'Address',
dataIndex: 'address',
width: '30%',
key: 'address',
},
];
const data = [
{
key: 1,
name: 'John Brown sr.',
age: 60,
address: 'New York No. 1 Lake Park',
children: [
{
key: 11,
name: 'John Brown',
age: 42,
address: 'New York No. 2 Lake Park',
},
{
key: 12,
name: 'John Brown jr.',
age: 30,
address: 'New York No. 3 Lake Park',
children: [
{
key: 121,
name: 'Jimmy Brown',
age: 16,
address: 'New York No. 3 Lake Park',
},
],
},
{
key: 13,
name: 'Jim Green sr.',
age: 72,
address: 'London No. 1 Lake Park',
children: [
{
key: 131,
name: 'Jim Green',
age: 42,
address: 'London No. 2 Lake Park',
children: [
{
key: 1311,
name: 'Jim Green jr.',
age: 25,
address: 'London No. 3 Lake Park',
},
{
key: 1312,
name: 'Jimmy Green sr.',
age: 18,
address: 'London No. 4 Lake Park',
},
],
},
],
},
],
},
{
key: 2,
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
},
];
const rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
},
onSelect: (record, selected, selectedRows) => {
console.log(record, selected, selectedRows);
},
onSelectAll: (selected, selectedRows, changeRows) => {
console.log(selected, selectedRows, changeRows);
},
};
export default {
data() {
return {
data,
columns,
rowSelection,
};
},
};
</script>
可展开 #
当表格内容较多不能一次性完全展示时。
<template>
<a-table :columns="columns" :dataSource="data">
<a slot="action" slot-scope="text" href="javascript:;">Delete</a>
<p slot="expandedRowRender" slot-scope="record" style="margin: 0">{{record.description}}</p>
</a-table>
</template>
<script>
const columns = [
{ title: 'Name', dataIndex: 'name', key: 'name' },
{ title: 'Age', dataIndex: 'age', key: 'age' },
{ title: 'Address', dataIndex: 'address', key: 'address' },
{ title: 'Action', dataIndex: '', key: 'x', scopedSlots: { customRender: 'action' } },
];
const data = [
{
key: 1,
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
description: 'My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park.',
},
{
key: 2,
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.',
},
{
key: 3,
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
description: 'My name is Joe Black, I am 32 years old, living in Sidney No. 1 Lake Park.',
},
];
export default {
data() {
return {
data,
columns,
};
},
};
</script>
固定头和列 #
适合同时展示有大量数据和数据列。
若列头与内容不对齐或出现列重复,请指定固定列的宽度
width
。
建议指定scroll.x
为大于表格宽度的固定值或百分比。注意,且非固定列宽度之和不要超过scroll.x
。
<template>
<a-table :columns="columns" :dataSource="data" :scroll="{ x: 1500, y: 300 }">
<a slot="action" slot-scope="text" href="javascript:;">action</a>
</a-table>
</template>
<script>
const columns = [
{ title: 'Full Name', width: 100, dataIndex: 'name', key: 'name', fixed: 'left' },
{ title: 'Age', width: 100, dataIndex: 'age', key: 'age', fixed: 'left' },
{ title: 'Column 1', dataIndex: 'address', key: '1', width: 150 },
{ title: 'Column 2', dataIndex: 'address', key: '2', width: 150 },
{ title: 'Column 3', dataIndex: 'address', key: '3', width: 150 },
{ title: 'Column 4', dataIndex: 'address', key: '4', width: 150 },
{ title: 'Column 5', dataIndex: 'address', key: '5', width: 150 },
{ title: 'Column 6', dataIndex: 'address', key: '6', width: 150 },
{ title: 'Column 7', dataIndex: 'address', key: '7', width: 150 },
{ title: 'Column 8', dataIndex: 'address', key: '8' },
{
title: 'Action',
key: 'operation',
fixed: 'right',
width: 100,
scopedSlots: { customRender: 'action' },
},
];
const data = [];
for (let i = 0; i < 100; i++) {
data.push({
key: i,
name: `Edrward ${i}`,
age: 32,
address: `London Park no. ${i}`,
});
}
export default {
data() {
return {
data,
columns,
};
},
};
</script>
固定列 #
对于列数很多的数据,可以固定前后的列,横向滚动查看其它数据,需要和 scroll.x
配合使用。
若列头与内容不对齐或出现列重复,请指定固定列的宽度
width
。
建议指定scroll.x
为大于表格宽度的固定值或百分比。注意,且非固定列宽度之和不要超过scroll.x
。
<template>
<a-table :columns="columns" :dataSource="data" :scroll="{ x: 1300 }">
<a slot="action" slot-scope="text" href="javascript:;">action</a>
</a-table>
</template>
<script>
const columns = [
{ title: 'Full Name', width: 100, dataIndex: 'name', key: 'name', fixed: 'left' },
{ title: 'Age', width: 100, dataIndex: 'age', key: 'age', fixed: 'left' },
{ title: 'Column 1', dataIndex: 'address', key: '1' },
{ title: 'Column 2', dataIndex: 'address', key: '2' },
{ title: 'Column 3', dataIndex: 'address', key: '3' },
{ title: 'Column 4', dataIndex: 'address', key: '4' },
{ title: 'Column 5', dataIndex: 'address', key: '5' },
{ title: 'Column 6', dataIndex: 'address', key: '6' },
{ title: 'Column 7', dataIndex: 'address', key: '7' },
{ title: 'Column 8', dataIndex: 'address', key: '8' },
{
title: 'Action',
key: 'operation',
fixed: 'right',
width: 100,
scopedSlots: { customRender: 'action' },
},
];
const data = [
{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York Park',
},
{
key: '2',
name: 'Jim Green',
age: 40,
address: 'London Park',
},
];
export default {
data() {
return {
data,
columns,
};
},
};
</script>
嵌套子表格 #
展示每行数据更详细的信息。
<template>
<a-table :columns="columns" :dataSource="data" class="components-table-demo-nested">
<a slot="operation" slot-scope="text" href="javascript:;">Publish</a>
<a-table
slot="expandedRowRender"
slot-scope="text"
:columns="innerColumns"
:dataSource="innerData"
:pagination="false"
>
<span slot="status" slot-scope="text"> <a-badge status="success" />Finished </span>
<span slot="operation" slot-scope="text" class="table-operation">
<a href="javascript:;">Pause</a>
<a href="javascript:;">Stop</a>
<a-dropdown>
<a-menu slot="overlay">
<a-menu-item>
Action 1
</a-menu-item>
<a-menu-item>
Action 2
</a-menu-item>
</a-menu>
<a href="javascript:;"> More <a-icon type="down" /> </a>
</a-dropdown>
</span>
</a-table>
</a-table>
</template>
<script>
const columns = [
{ title: 'Name', dataIndex: 'name', key: 'name' },
{ title: 'Platform', dataIndex: 'platform', key: 'platform' },
{ title: 'Version', dataIndex: 'version', key: 'version' },
{ title: 'Upgraded', dataIndex: 'upgradeNum', key: 'upgradeNum' },
{ title: 'Creator', dataIndex: 'creator', key: 'creator' },
{ title: 'Date', dataIndex: 'createdAt', key: 'createdAt' },
{ title: 'Action', key: 'operation', scopedSlots: { customRender: 'operation' } },
];
const data = [];
for (let i = 0; i < 3; ++i) {
data.push({
key: i,
name: 'Screem',
platform: 'iOS',
version: '10.3.4.5654',
upgradeNum: 500,
creator: 'Jack',
createdAt: '2014-12-24 23:12:00',
});
}
const innerColumns = [
{ title: 'Date', dataIndex: 'date', key: 'date' },
{ title: 'Name', dataIndex: 'name', key: 'name' },
{ title: 'Status', key: 'state', scopedSlots: { customRender: 'status' } },
{ title: 'Upgrade Status', dataIndex: 'upgradeNum', key: 'upgradeNum' },
{
title: 'Action',
dataIndex: 'operation',
key: 'operation',
scopedSlots: { customRender: 'operation' },
},
];
const innerData = [];
for (let i = 0; i < 3; ++i) {
innerData.push({
key: i,
date: '2014-12-24 23:12:00',
name: 'This is production name',
upgradeNum: 'Upgraded: 56',
});
}
export default {
data() {
return {
data,
columns,
innerColumns,
innerData,
};
},
};
</script>
API #
Table #
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
bordered | 是否展示外边框和列边框 | boolean | false |
childrenColumnName | 指定树形结构的列名 | string[] | children |
columns | 表格列的配置描述,具体项见下表 | array | - |
components | 覆盖默认的 table 元素 | object | - |
dataSource | 数据数组 | any[] | |
defaultExpandAllRows | 初始时,是否展开所有行 | boolean | false |
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 | 通过点击行来展开子行 | boolean | false |
footer | 表格尾部 | Function(currentPageData)|slot-scope | |
indentSize | 展示树形数据时,每层缩进的宽度,以 px 为单位 | number | 15 |
loading | 页面是否加载中 | boolean|object | false |
locale | 默认文案设置,目前包括排序、过滤、空数据文案 | object | filterConfirm: '确定' filterReset: '重置' emptyText: '暂无数据' |
pagination | 分页器,参考配置项或 pagination文档,设为 false 时不展示和进行分页 | object | |
rowClassName | 表格行的类名 | Function(record, index):string | - |
rowKey | 表格行 key 的取值,可以是字符串或一个函数 | string|Function(record):string | 'key' |
rowSelection | 列表项是否可选择,配置项 | object | null |
scroll | 设置横向或纵向滚动,也可用于指定滚动区域的宽和高,建议为 x 设置一个数字,如果要设置为 true ,需要配合样式 .ant-table td { white-space: nowrap; } | { x: number | true, y: number } | - |
showHeader | 是否显示表头 | boolean | true |
size | 表格大小 | default | middle | small | default |
title | 表格标题 | Function(currentPageData)|slot-scope | |
customHeaderRow | 设置头部行属性 | Function(column, index) | - |
customRow | 设置行属性 | Function(record, index) | - |
事件 #
事件名称 | 说明 | 回调参数 |
---|---|---|
expandedRowsChange | 展开的行变化时触发 | Function(expandedRows) |
change | 分页、排序、筛选变化时触发 | Function(pagination, filters, sorter) |
expand | 点击展开图标时触发 | Function(expanded, record) |
customRow 用法 #
适用于 customRow
customHeaderRow
customCell
customHeaderCell
。遵循Vue jsx语法。
<Table
customRow={(record) => {
return {
props: {
xxx... //属性
},
on: { // 事件
click: (event) => {}, // 点击行
doubleclick: (event) => {},
contextmenu: (event) => {},
mouseenter: (event) => {}, // 鼠标移入行
mouseleave: (event) => {}
},
};
)}
customHeaderRow={(column) => {
return {
on: {
click: () => {}, // 点击表头行
}
};
)}
/>
Column #
列描述数据对象,是 columns 中的一项,Column 使用相同的 API。
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
align | 设置列内容的对齐方式 | 'left' | 'right' | 'center' | 'left' |
colSpan | 表头列合并,设置为 0 时,不渲染 | number | |
dataIndex | 列数据在数据项中对应的 key,支持 a.b.c 的嵌套写法 | string | - |
filterDropdown | 可以自定义筛选菜单,此函数只负责渲染图层,需要自行编写各种交互 | VNode | slot-scope | - |
filterDropdownVisible | 用于控制自定义筛选菜单是否可见 | boolean | - |
filtered | 标识数据是否经过过滤,筛选图标会高亮 | boolean | false |
filteredValue | 筛选的受控属性,外界可用此控制列的筛选状态,值为已筛选的 value 数组 | string[] | - |
filterIcon | 自定义 fiter 图标。 | VNode | (filtered: boolean, column: Column) => vNode |slot |slot-scope | false |
filterMultiple | 是否多选 | boolean | true |
filters | 表头的筛选菜单项 | object[] | - |
fixed | 列是否固定,可选 true (等效于 left) 'left' 'right' | boolean|string | false |
key | Vue 需要的 key,如果已经设置了唯一的 dataIndex ,可以忽略这个属性 | string | - |
customRender | 生成复杂数据的渲染函数,参数分别为当前行的值,当前行数据,行索引,@return 里面可以设置表格行/列合并,可参考 demo 表格行/列合并 | Function(text, record, index) {}|slot-scope | - |
sorter | 排序函数,本地排序使用一个函数(参考 Array.sort 的 compareFunction),需要服务端排序可设为 true | Function|boolean | - |
sortOrder | 排序的受控属性,外界可用此控制列的排序,可设置为 'ascend' 'descend' false | boolean|string | - |
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 | 去掉『全选』『反选』两个默认选项 | boolean | false |
selectedRowKeys | 指定选中项的 key 数组,需要和 onChange 进行配合 | string[] | [] |
selections | 自定义选择配置项, 设为 true 时使用默认选择项 | object[]|boolean | true |
type | 多选/单选,checkbox or radio | string | checkbox |
onChange | 选中项发生变化时的回调 | Function(selectedRowKeys, selectedRows) | - |
onSelect | 用户手动选择/取消选择某列的回调 | Function(record, selected, selectedRows, nativeEvent) | - |
onSelectAll | 用户手动选择/取消选择所有列的回调 | Function(selected, selectedRows, changeRows) | - |
onSelectInvert | 用户手动选择反选的回调 | Function(selectedRows) | - |
selection #
自定义选择配置项
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
key | Vue 需要的 key,建议设置 | string | - |
text | 选择项显示的文字 | string|VNode | - |
onSelect | 选择项点击回调 | Function(changeableRowKeys) | - |
注意 #
在 Table 中,dataSource
和 columns
里的数据值都需要指定 key
值。对于 dataSource
默认将每列数据的 key
属性作为唯一的标识。
如果你的数据没有这个属性,务必使用 rowKey
来指定数据列的主键。若没有指定,控制台会出现缺少 key 的提示,表格组件也会出现各类奇怪的错误。
// 比如你的数据主键是 uid
return <Table rowKey="uid" />;
// 或
return <Table rowKey={record => record.uid} />;