Table 表格
展示行列数据。
何时使用
- 当有大量结构化的数据需要展现时;
- 当需要对数据进行排序、搜索、分页、自定义操作等复杂行为时。
如何使用
指定表格的数据源 dataSource 为一个数组。
js
const dataSource = [
{
key: '1',
name: '胡彦斌',
age: 32,
address: '西湖区湖底公园1号',
},
{
key: '2',
name: '胡彦祖',
age: 42,
address: '西湖区湖底公园1号',
},
];
const columns = [
{
title: '姓名',
dataIndex: 'name',
key: 'name',
},
{
title: '年龄',
dataIndex: 'age',
key: 'age',
},
{
title: '住址',
dataIndex: 'address',
key: 'address',
},
];基本用法
简单的表格,最后一列是各种操作。
vue
<template>
<g-table :data-source="dataSource" :columns="columns">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'name'">
<a>{{ record.name }}</a>
</template>
<template v-else-if="column.key === 'tags'">
<span>
<g-tag
v-for="tag in record.tags"
:key="tag"
:color="tag === 'loser' ? 'volcano' : tag.length > 5 ? 'geekblue' : 'green'"
>
{{ tag.toUpperCase() }}
</g-tag>
</span>
</template>
<template v-else-if="column.key === 'action'">
<span>
<a>Invite 一 {{ record.name }}</a>
<g-divider type="vertical" />
<a>Delete</a>
</span>
</template>
</template>
</g-table>
</template>
<script>
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
},
{
title: 'Address',
dataIndex: 'address',
key: 'address',
},
{
title: 'Tags',
key: 'tags',
dataIndex: 'tags',
},
{
title: 'Action',
key: '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 {
setup() {
return {
dataSource: data,
columns,
};
},
};
</script>选择和操作
选择后进行操作,完成后清空选择,通过 rowSelection.selectedRowKeys 来控制选中项。
vue
<template>
<div>
<div style="margin-bottom: 16px">
<g-button type="primary" :disabled="!hasSelected" :loading="loading" @click="start">
Reload
</g-button>
<span style="margin-left: 8px">
<template v-if="hasSelected">
{{ `Selected ${selectedRowKeys.length} items` }}
</template>
</span>
</div>
<g-table :row-selection="rowSelection" :columns="columns" :data-source="data" />
</div>
</template>
<script>
import { computed, ref } from 'vue';
const columns = [
{
title: 'Name',
dataIndex: 'name',
},
{
title: 'Age',
dataIndex: 'age',
},
{
title: 'Address',
dataIndex: 'address',
},
];
const data = [];
for (let i = 0; i < 46; i++) {
data.push({
key: i,
name: `Edward King ${i}`,
age: 32,
address: `London, Park Lane no. ${i}`,
});
}
export default {
setup() {
const selectedRowKeys = ref([]);
const loading = ref(false);
const hasSelected = computed(() => selectedRowKeys.value.length > 0);
const start = () => {
loading.value = true;
// ajax request after empty completing
setTimeout(() => {
selectedRowKeys.value = [];
loading.value = false;
}, 1000);
};
const onSelectChange = (newSelectedRowKeys) => {
console.log('selectedRowKeys changed: ', newSelectedRowKeys);
selectedRowKeys.value = newSelectedRowKeys;
};
const rowSelection = {
selectedRowKeys,
onChange: onSelectChange,
};
return {
data,
columns,
rowSelection,
selectedRowKeys,
loading,
hasSelected,
start,
};
},
};
</script>排序和筛选
对某一列数据进行筛选,使用列的 filters 属性来指定需要筛选菜单的列,onFilter 用于筛选当前数据,filterMultiple 用于指定多选和单选。
对某一列数据进行排序,通过指定列的 sorter 函数即可启动排序功能。sorter: function(a, b) { return a.age - b.age }, sorter 也可以是一个 boolean 属性,如果想要服务端排序,可以设置为 true。
vue
<template>
<g-table :columns="columns" :data-source="data" @change="onChange" />
</template>
<script>
const columns = [
{
title: 'Name',
dataIndex: 'name',
filters: [
{
text: 'Joe',
value: 'Joe',
},
{
text: 'Jim',
value: 'Jim',
},
],
// specify the condition of filtering result
// here is that finding the name started with `value`
onFilter: (value, record) => record.name.indexOf(value) === 0,
sorter: (a, b) => a.name.length - b.name.length,
sortDirections: ['descend'],
},
{
title: 'Age',
dataIndex: 'age',
defaultSortOrder: 'descend',
sorter: (a, b) => a.age - b.age,
},
{
title: 'Address',
dataIndex: 'address',
filters: [
{
text: 'London',
value: 'London',
},
{
text: 'New York',
value: 'New York',
},
],
filterMultiple: false,
onFilter: (value, record) => record.address.indexOf(value) === 0,
sorter: (a, b) => a.address.length - b.address.length,
sortDirections: ['descend', 'ascend'],
},
];
const data = [
{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
},
{
key: '2',
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
},
{
key: '3',
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
},
{
key: '4',
name: 'Jim Red',
age: 32,
address: 'London No. 2 Lake Park',
},
];
export default {
setup() {
const onChange = (pagination, filters, sorter, extra) => {
console.log('params', pagination, filters, sorter, extra);
};
return {
data,
columns,
onChange,
};
},
};
</script>可展开
当表格内容较多不能一次性完全展示时。
vue
<template>
<g-table
:columns="columns"
:data-source="data"
:expand-row-by-click="true"
>
<template #expandedRowRender="{ record }">
<p style="margin: 0">
{{ record.description }}
</p>
</template>
</g-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: 'operation',
key: 'operation',
},
];
const data = [];
for (let i = 0; i < 3; ++i) {
data.push({
key: i,
name: 'Screem',
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.',
});
}
export default {
setup() {
return {
data,
columns,
};
},
};
</script>固定列
对于列数很多的数据,可以固定前后的列,横向滚动查看其它数据,需要和 scroll.x 配合使用。
若列头与内容不对齐或出现列重复,请指定固定列的宽度
width。如果指定width不生效或出现白色垂直空隙,请尝试建议留一列不设宽度以适应弹性布局,或者检查是否有超长连续字段破坏布局。
vue
<template>
<g-table :columns="columns" :data-source="data" :scroll="{ x: 1500, y: 300 }" />
</template>
<script>
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
fixed: 'left',
width: 100,
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
fixed: 'left',
width: 100,
},
{
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,
},
];
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 {
setup() {
return {
data,
columns,
};
},
};
</script>固定头和列
适合同时展示有大量数据和数据列。
若列头与内容不对齐或出现列重复,请指定固定列的宽度
width。 建议指定scroll.x为大于表格宽度的固定值或百分比。注意,且非固定列宽度之和不要超过scroll.x。
vue
<template>
<g-table
:columns="columns"
:data-source="data"
:scroll="{ x: 1500, y: 300 }"
bordered
/>
</template>
<script>
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
fixed: 'left',
width: 100,
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
fixed: 'left',
width: 100,
},
{
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,
},
];
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 {
setup() {
return {
data,
columns,
};
},
};
</script>表头分组
columns[n] 可以内嵌 children,以渲染分组表头。
vue
<template>
<g-table :columns="columns" :data-source="data" bordered />
</template>
<script>
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
width: 100,
fixed: 'left',
filters: [
{
text: 'Joe',
value: 'Joe',
},
{
text: 'John',
value: 'John',
},
],
onFilter: (value, record) => record.name.indexOf(value) === 0,
},
{
title: 'Other',
children: [
{
title: 'Age',
dataIndex: 'age',
key: 'age',
width: 150,
sorter: (a, b) => a.age - b.age,
},
{
title: 'Address',
children: [
{
title: 'Street',
dataIndex: 'street',
key: 'street',
width: 150,
},
{
title: 'Block',
children: [
{
title: 'Building',
dataIndex: 'building',
key: 'building',
width: 100,
},
{
title: 'Door No.',
dataIndex: 'number',
key: 'number',
width: 100,
},
],
},
],
},
],
},
{
title: 'Company',
children: [
{
title: 'Company Address',
dataIndex: 'companyAddress',
key: 'companyAddress',
width: 200,
},
{
title: 'Company Name',
dataIndex: 'companyName',
key: 'companyName',
},
],
},
{
title: 'Gender',
dataIndex: 'gender',
key: 'gender',
width: 80,
fixed: 'right',
},
];
const data = [];
for (let i = 0; i < 100; i++) {
data.push({
key: i,
name: 'John Brown',
age: i + 1,
street: 'Lake Park',
building: 'C',
number: 2035,
companyAddress: 'Lake Street 42',
companyName: 'SoftLake Co',
gender: 'M',
});
}
export default {
setup() {
return {
data,
columns,
};
},
};
</script>可编辑单元格
带单元格编辑功能的表格。
vue
<template>
<g-table :data-source="dataSource" :columns="columns" bordered>
<template #bodyCell="{ column, text, record, index }">
<template v-if="column.dataIndex === 'name'">
<div>
<g-input
v-if="editableData[record.key]"
v-model:value="editableData[record.key].name"
style="margin: -5px 0"
/>
<template v-else>
{{ text }}
</template>
</div>
</template>
<template v-else-if="column.dataIndex === 'operation'">
<div class="editable-row-operations">
<span v-if="editableData[record.key]">
<g-typography-link @click="save(record.key)">Save</g-typography-link>
<g-popconfirm title="Sure to cancel?" @confirm="cancel(record.key)">
<a>Cancel</a>
</g-popconfirm>
</span>
<span v-else>
<a @click="edit(record.key)">Edit</a>
</span>
</div>
</template>
</template>
</g-table>
</template>
<script>
import { cloneDeep } from 'lodash-es';
import { reactive, ref } from 'vue';
const columns = [
{
title: 'name',
dataIndex: 'name',
width: '25%',
},
{
title: 'age',
dataIndex: 'age',
width: '15%',
},
{
title: 'address',
dataIndex: 'address',
width: '40%',
},
{
title: 'operation',
dataIndex: '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 {
setup() {
const dataSource = ref(data);
const editableData = reactive({});
const edit = (key) => {
editableData[key] = cloneDeep(dataSource.value.filter(item => key === item.key)[0]);
};
const save = (key) => {
Object.assign(dataSource.value.filter(item => key === item.key)[0], editableData[key]);
delete editableData[key];
};
const cancel = (key) => {
delete editableData[key];
};
return {
dataSource,
columns,
editableData,
edit,
save,
cancel,
};
},
};
</script>
<style>
.editable-row-operations a {
margin-right: 8px;
}
</style>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 | v-slot:expandedRowRender="{record, index, indent, expanded}" | - | |
| expandIcon | 自定义展开图标,参考示例 | Function(props):VNode | v-slot:expandIcon="props" | - | |
| expandRowByClick | 通过点击行来展开子行 | boolean | false | |
| footer | 表格尾部 | Function(currentPageData) | v-slot:footer="currentPageData" | - | |
| getPopupContainer | 设置表格内各类浮层的渲染节点,如筛选菜单 | (triggerNode) => HTMLElement | () => TableHtmlElement | |
| indentSize | 展示树形数据时,每层缩进的宽度,以 px 为单位 | number | 15 | |
| loading | 页面是否加载中 | boolean| object | false | |
| locale | 默认文案设置,目前包括排序、过滤、空数据文案 | object | filterConfirm: '确定' filterReset: '重置' emptyText: '暂无数据' | |
| pagination | 分页器,参考配置项或 pagination 文档,设为 false 时不展示和进行分页 | object | false | - | |
| rowClassName | 表格行的类名 | Function(record, index):string | - | |
| rowKey | 表格行 key 的取值,可以是字符串或一个函数 | string|Function(record):string | 'key' | |
| rowSelection | 表格行是否可选择,配置项 | object | - | |
| scroll | 表格是否可滚动,也可以指定滚动区域的宽、高,配置项 | object | - | |
| showHeader | 是否显示表头 | boolean | true | |
| showSorterTooltip | 表头是否显示下次排序的 tooltip 提示。当参数类型为对象时,将被设置为 Tooltip 的属性 | boolean | Tooltip props | true | |
| size | 表格大小 | default | middle | small | default | |
| sortDirections | 支持的排序方式,取值为 ascend descend | Array | [ascend, descend] | |
| sticky | 设置粘性头部和滚动条 | boolean | {offsetHeader?: number, offsetScroll?: number, getContainer?: () => HTMLElement} | - | 4.0.0 |
| summary | 总结栏 | v-slot:summary | - | |
| tableLayout | 表格元素的 table-layout 属性,设为 fixed 表示内容不会影响列的布局 | - | 'auto' | 'fixed' | 无 固定表头/列或使用了 column.ellipsis 时,默认值为 fixed | |
| title | 表格标题 | Function(currentPageData) | v-slot:title="currentPageData" | - | |
| transformCellText | 数据渲染前可以再次改变,一般用户空数据的默认配置 | Function({ text, column, record, index }) => any | - | 1.5.4 |
事件
| 事件名称 | 说明 | 回调参数 |
|---|---|---|
| change | 分页、排序、筛选变化时触发 | Function(pagination, filters, sorter, { currentDataSource }) |
| expand | 点击展开图标时触发 | Function(expanded, record) |
| expandedRowsChange | 展开的行变化时触发 | Function(expandedRows) |
| resizeColumn | 拖拽列时触发 | Function(width, column) |
Column
列描述数据对象,是 columns 中的一项,Column 使用相同的 API。
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|---|---|---|---|---|
| align | 设置列的对齐方式 | left | right | center | left | |
| colSpan | 表头列合并,设置为 0 时,不渲染 | number | - | |
| dataIndex | 列数据在数据项中对应的路径,支持通过数组查询嵌套路径 | string | string[] | - | |
| defaultFilteredValue | 默认筛选值 | string[] | - | |
| defaultSortOrder | 默认排序顺序 | ascend | descend | - | |
| ellipsis | 超过宽度将自动省略,暂不支持和排序筛选一起使用。 设置为 true 或 { showTitle?: boolean } 时,表格布局将变成 tableLayout="fixed"。 | boolean | | false | |
| filterDropdown | 可以自定义筛选菜单,此函数只负责渲染图层,需要自行编写各种交互 | VNode | (props: FilterDropdownProps) => VNode | - | |
| filterDropdownVisible | 用于控制自定义筛选菜单是否可见 | boolean | - | |
| filtered | 标识数据是否经过过滤,筛选图标会高亮 | boolean | false | |
| filteredValue | 筛选的受控属性,外界可用此控制列的筛选状态,值为已筛选的 value 数组 | string[] | - | |
| filterIcon | 自定义 filter 图标。 | VNode | ({filtered: boolean, column: Column}) => vNode | false | |
| filterMultiple | 是否多选 | boolean | true | |
| filters | 表头的筛选菜单项 | object[] | - | |
| fixed | (IE 下无效)列是否固定,可选 true (等效于 left) left right | boolean | string | false | |
| key | Vue 需要的 key,如果已经设置了唯一的 dataIndex,可以忽略这个属性 | string | - | |
| maxWidth | 拖拽列最大宽度,会受到表格自动调整分配宽度影响 | number | - | 1.5.0 |
| minWidth | 拖拽列最小宽度,会受到表格自动调整分配宽度影响 | number | 50 | 1.5.0 |
| resizable | 是否可拖拽调整宽度,此时 width 必须是 number 类型 | boolean | - | 1.5.0 |
| responsive | 响应式 breakpoint 配置列表。未设置则始终可见。 | Breakpoint[] | - | 1.5.0 |
| rowScope | 设置列范围 | row | rowgroup | - | 4.1.0 |
| showSorterTooltip | 表头显示下次排序的 tooltip 提示, 覆盖 table 中 showSorterTooltip | boolean | Tooltip props | true | |
| sortDirections | 支持的排序方式,覆盖 Table 中 sortDirections, 取值为 ascend descend | Array | [ascend, descend] | |
| sorter | 排序函数,本地排序使用一个函数(参考 Array.sort 的 compareFunction),需要服务端排序可设为 true | Function | boolean | - | |
| sortOrder | 排序的受控属性,外界可用此控制列的排序,可设置为 ascend descend false | boolean | string | - | |
| title | 列头显示文字(函数用法 3.0.0 后支持) | string | VNode | (props: { filters: TableColumnFilter[], sortOrder: SortOrder, sortColumn: TableColumn }) => VNode | - | |
| width | 列宽度(指定了也不生效?) | string | number | - | |
| customCell | 设置单元格属性 | Function(record, rowIndex) | - | |
| customHeaderCell | 设置头部单元格属性 | Function(column) | - | |
| onFilter | 本地模式下,确定筛选的运行函数 | Function | - | |
| onFilterDropdownVisibleChange | 自定义筛选菜单可见性改变时调用 | function(visible) {} | - | |
| slots | 使用 columns 时,可以通过该属性配置支持 slot 的属性,如 slots: { title: 'XXX'} | object | - |
rowSelection
选择功能的配置。
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|---|---|---|---|---|
| checkStrictly | checkable 状态下节点选择完全受控(父子节点选中状态不再关联) | boolean | true | 4.0.0 |
| columnWidth | 自定义列表选择框宽度 | string | number | 32px | |
| columnTitle | 自定义列表选择框标题 | string | VNode | - | |
| fixed | 把选择框列固定在左边 | boolean | - | |
| getCheckboxProps | 选择框的默认属性配置 | Function(record) | - | |
| hideSelectAll | 隐藏全选勾选框与自定义选择项 | boolean | false | 4.3.0 |
| preserveSelectedRowKeys | 当数据被删除时仍然保留选项的 key | boolean | - | 4.0.0 |
| renderCell | 渲染勾选框,用法与 Column 的 customCell 相同 | Function(checked, record, index, originNode) | - | 4.1.0 |
| selectedRowKeys | 指定选中项的 key 数组,需要和 onChange 进行配合 | string[] | number[] | [] | |
| 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(selectedRowKeys) | - | |
| onSelectNone | 用户清空选择的回调 | Function() | - | 4.0.0 |
scroll
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| scrollToFirstRowOnChange | 当分页、排序、筛选变化后是否滚动到表格顶部 | boolean | - |
| x | 设置横向滚动,也可用于指定滚动区域的宽,可以设置为像素值,百分比,true 和 'max-content' | string | number | true | - |
| y | 设置纵向滚动,也可用于指定滚动区域的高,可以设置为像素值 | string | number | - |
selection
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| key | Vue 需要的 key,建议设置 | string | - |
| text | 选择项显示的文字 | string | VNode | - |
| onSelect | 选择项点击回调 | Function(changeableRowKeys) | - |
注意
按照 Vue 的规范,所有的数组必须有 key 属性,否则 table 的某些功能可能会出现问题。
js
// 比如你的数据主键是 uid
return <Table rowKey="uid" />;
// 或
return <Table rowKey={record => record.uid} />;