本目录提供两个组件,共用同一套列定义(ColumnDef):
| 组件 | 定位 | 能力 |
|---|
Table | 通用表格 | 自动/自定义列、排序、行选择、可展开行、加载与空状态、吸顶、列插槽、tableApi 逃生舱 |
PageTable | 分页表格(特殊组件) | 在通用能力之外封装列表页固定套路:搜索、分页、列管理、行操作、无限滚动、服务端排序 |
- 只是把数据以表格形式展示,需要排序 / 行选择 / 展开行 / 单元格自定义 → 用
Table。 - 后台列表页:需要搜索、分页、批量选择、行操作、列显示设置 → 用
PageTable。 - 数据量大或字段多、需要服务端排序 / 无限滚动 → 用
PageTable。
import { Table, PageTable } from "@reglow/reui";
import type { TableColumn, TableProps, PageTableProps, RowAction } from "@reglow/reui";
基础表格原子组件(TableRoot / TableHeader / TableBody / TableRow / TableHead / TableCell)也从同一入口导出,TableRoot 即裸 <table> 容器,用于自建表格或给 Table 的插槽打底。
不传 columns 时,按首行对象的 key 自动生成列,适合快速预览数据。
<script setup lang="ts">
const data = [
{ id: "4600", email: "james.anderson@example.com", status: "paid", amount: 594 },
{ id: "4599", email: "mia.white@example.com", status: "failed", amount: 276 },
{ id: "4598", email: "william.brown@example.com", status: "refunded", amount: 315 },
];
</script>
<template>
<Table :data="data" />
</template>
columns 就是 TanStack 的 ColumnDef,header / cell / footer 支持字符串或渲染函数;
meta.class / meta.style 作用于 th、td,meta.colspan / meta.rowspan 可合并单元格。
表格级 meta.class.tr 控制整行 class,传函数即可按行返回不同样式。
<script setup lang="ts">
import type { Row } from "@tanstack/vue-table";
import { Badge, Table } from "@reglow/reui";
import type { TableColumn } from "@reglow/reui";
interface Payment {
id: string;
email: string;
status: "paid" | "failed" | "refunded";
amount: number;
}
const data: Payment[] = [
{ id: "4600", email: "james.anderson@example.com", status: "paid", amount: 594 },
{ id: "4599", email: "mia.white@example.com", status: "failed", amount: 276 },
];
/** 行级样式:按行返回 class(函数在 script 中定义,避免模板内联箭头函数) */
function rowClass(row: Row<Payment>) {
return row.original.status === "failed" ? "bg-destructive/10" : "";
}
const meta = { class: { tr: rowClass } };
const columns: TableColumn<Payment>[] = [
{ accessorKey: "id", header: "#" },
{ accessorKey: "email", header: "邮箱" },
{ accessorKey: "status", header: "状态" },
{
accessorKey: "amount",
header: "金额",
meta: { class: { th: "text-right", td: "text-right font-medium" } },
},
];
</script>
<template>
<Table :columns="columns" :data="data" :meta="meta" caption="支付记录">
<template #status-cell="{ row }">
<Badge :variant="row.original.status === 'paid' ? 'success' : 'destructive'">
{{ row.original.status }}
</Badge>
</template>
</Table>
</template>
可排序列的表头自动带点击排序,在「升序 / 降序 / 取消排序」之间循环(数值列首次点击为降序,与 TanStack 默认一致)。
表头内容仍由 header 决定,需要排序指示器时用 #<列id>-header 插槽读取 column.getIsSorted()(不要在外层再绑定点击,避免重复触发)。
<script setup lang="ts">
import { ArrowDown, ArrowUp, ArrowUpDown } from "lucide-vue-next";
import type { TableColumn } from "@reglow/reui";
interface Stature {
name: string;
height: number;
weight: number;
}
const data: Stature[] = [
{ name: "张三", height: 178, weight: 68 },
{ name: "李四", height: 165, weight: 54 },
{ name: "王五", height: 182, weight: 76 },
];
const columns: TableColumn<Stature>[] = [
{ accessorKey: "name", header: "姓名" },
{ accessorKey: "height", header: "身高(cm)" },
{ accessorKey: "weight", header: "体重(kg)" },
];
</script>
<template>
<Table :columns="columns" :data="data">
<template #height-header="{ column }">
<span class="inline-flex items-center gap-1">
身高(cm)
<ArrowUp v-if="column.getIsSorted() === 'asc'" class="h-3.5 w-3.5" />
<ArrowDown v-else-if="column.getIsSorted() === 'desc'" class="h-3.5 w-3.5" />
<ArrowUpDown v-else class="h-3.5 w-3.5 opacity-50" />
</span>
</template>
</Table>
</template>
服务端排序时用 v-model:sorting 接管排序状态(组件只上报,不本地排序):
<template>
<Table v-model:sorting="sorting" :columns="columns" :data="list" @update:sorting="load" />
</template>
在 columns 里自己定义一个选择列(配置更灵活),配合 v-model:row-selection 取选中结果。
<script setup lang="ts">
import { computed, ref } from "vue";
import type { RowSelectionState } from "@tanstack/vue-table";
import { Checkbox, Table } from "@reglow/reui";
import type { TableColumn } from "@reglow/reui";
interface User {
id: string;
name: string;
email: string;
}
const data: User[] = [
{ id: "1", name: "陈晨", email: "chen@reglow.ai" },
{ id: "2", name: "林一", email: "lin@reglow.ai" },
];
const rowSelection = ref<RowSelectionState>({});
const selectedCount = computed(() => Object.keys(rowSelection.value).length);
const columns: TableColumn<User>[] = [
{ id: "select", header: "", enableSorting: false, meta: { class: { th: "w-10", td: "w-10" } } },
{ accessorKey: "name", header: "姓名" },
{ accessorKey: "email", header: "邮箱" },
];
</script>
<template>
<div class="space-y-2">
<Table :columns="columns" :data="data" v-model:row-selection="rowSelection">
<template #select-header="{ table }">
<Checkbox
:checked="table.getIsAllPageRowsSelected()"
:indeterminate="table.getIsSomePageRowsSelected() && !table.getIsAllPageRowsSelected()"
@update:checked="(value: boolean) => table.toggleAllPageRowsSelected(value)"
/>
</template>
<template #select-cell="{ row }">
<Checkbox
:checked="row.getIsSelected()"
@update:checked="(value: boolean) => row.toggleSelected(value)"
/>
</template>
</Table>
<p class="text-sm text-muted-foreground">已选 {{ selectedCount }} 项</p>
</div>
</template>
行展开状态由 TanStack 维护:列里的按钮调用 row.toggleExpanded(),展开内容通过 #expanded 插槽渲染(默认渲染 row.original)。
v-model:expanded 可回灌 / 预设展开状态。
<script setup lang="ts">
import { ref } from "vue";
import { ChevronRight } from "lucide-vue-next";
import type { ExpandedState } from "@tanstack/vue-table";
import { Table } from "@reglow/reui";
import type { TableColumn } from "@reglow/reui";
interface Order {
id: string;
customer: string;
amount: number;
address: string;
}
const data: Order[] = [
{ id: "4600", customer: "张三", amount: 594, address: "杭州市西湖区文三路 100 号" },
{ id: "4599", customer: "李四", amount: 276, address: "上海市浦东新区世纪大道 1 号" },
];
/** 默认展开第一行 */
const expanded = ref<ExpandedState>({ "0": true });
const columns: TableColumn<Order>[] = [
{ id: "expand", header: "", enableSorting: false, meta: { class: { th: "w-10", td: "w-10" } } },
{ accessorKey: "id", header: "订单号" },
{ accessorKey: "customer", header: "客户" },
{ accessorKey: "amount", header: "金额", meta: { class: { th: "text-right", td: "text-right font-medium" } } },
];
</script>
<template>
<Table v-model:expanded="expanded" :columns="columns" :data="data">
<template #expand-cell="{ row }">
<button
type="button"
class="flex h-6 w-6 cursor-pointer items-center justify-center rounded hover:bg-muted"
:aria-label="row.getIsExpanded() ? '收起' : '展开'"
@click="row.toggleExpanded()"
>
<ChevronRight
class="h-4 w-4 transition-transform duration-200"
:class="row.getIsExpanded() ? 'rotate-90' : ''"
/>
</button>
</template>
<template #expanded="{ row }">
<div class="grid gap-1 text-sm">
<div>收货地址:{{ row.original.address }}</div>
<div>订单金额:€{{ row.original.amount }}</div>
</div>
</template>
</Table>
</template>
loading 时顶部显示加载条(loading-animation 支持 carousel / carousel-inverse / pulse,loading-color 控制颜色);
无数据时表体展示 #loading 插槽(默认「加载中」),未处于加载态时展示内置插画占位 + empty 文案(默认 i18n common.noData,即「暂无数据」),也可用 #empty 插槽完全替换。
<script setup lang="ts">
import { ref } from "vue";
import { Table } from "@reglow/reui";
import type { TableColumn } from "@reglow/reui";
const columns: TableColumn<{ id: string; name: string }>[] = [
{ accessorKey: "id", header: "编号" },
{ accessorKey: "name", header: "任务" },
];
const rows = [
{ id: "T-01", name: "设计评审" },
{ id: "T-02", name: "接口联调" },
];
const loading = ref(false);
const isEmpty = ref(false);
</script>
<template>
<Table
:columns="columns"
:data="isEmpty ? [] : rows"
:loading="loading"
loading-animation="pulse"
empty="暂无任务"
/>
</template>
sticky 可为 true(表头 + 表尾)/ "header" / "footer",需外层限定高度(直接给 Table 加高度类即可);
size 控制行密度(sm / md / lg),striped 开启斑马纹,bordered 显示边框网格。
<template>
<Table :columns="columns" :data="data" sticky class="max-h-[320px]" />
<Table :columns="columns" :data="data" size="sm" striped bordered />
</template>
| 插槽 | 说明 | 参数 |
|---|
caption | 表格标题 | - |
body-top | 表体首行之前 | { table } |
body-bottom | 表体末尾 | { table } |
empty | 空数据 | - |
loading | 加载中(无数据时) | - |
expanded | 展开行内容 | { row, table } |
<列id>-header | 自定义表头单元格 | { header, column, table } |
<列id>-cell | 自定义数据单元格 | { row, column, cell, table } |
<列id>-footer | 自定义表尾单元格 | { header, column, table } |
<script setup lang="ts">
// body-top / body-bottom 里可以直接写 TableRow / TableCell
import { Table, TableCell, TableRow } from "@reglow/reui";
</script>
<template>
<Table :columns="columns" :data="data">
<template #body-top>
<TableRow class="hover:bg-transparent">
<TableCell :colspan="columns.length" class="bg-muted/40 text-xs">
共 {{ data.length }} 条记录
</TableCell>
</TableRow>
</template>
<template #status-cell="{ row }">
<Badge v-if="row.original.status === 'paid'" variant="success">已支付</Badge>
<span v-else class="text-muted-foreground">—</span>
</template>
</Table>
</template>
组件 expose 了 TanStack 实例 tableApi,筛选、列可见性、行模型等能力可直接操作。
<script setup lang="ts">
import { ref } from "vue";
import { Input, Table } from "@reglow/reui";
const tableRef = ref();
function filterEmails(keyword: string) {
tableRef.value?.tableApi.getColumn("email")?.setFilterValue(keyword);
}
</script>
<template>
<div class="space-y-2">
<Input placeholder="筛选邮箱…" @update:model-value="filterEmails" />
<Table ref="tableRef" :columns="columns" :data="data" />
</div>
</template>
| 参数 | 说明 | 类型 | 默认值 |
|---|
| data | 表格数据 | TData[] | [] |
| columns | 列定义;不传时按首行 key 自动生成 | TableColumn[] | - |
| caption | 表格标题 | string | - |
| empty | 空数据文案 | string | i18n common.noData |
| meta | 表格级 meta(class.tr) | TableMetaConfig | - |
| sticky | 吸顶 | boolean | "header" | "footer" | false |
| loading | 加载中 | boolean | false |
| loadingColor | 加载条颜色 | string | currentColor |
| loadingAnimation | 加载条动画 | carousel | carousel-inverse | pulse | carousel |
| size | 行密度 | sm | md | lg | md |
| striped | 斑马纹 | boolean | false |
| bordered | 边框网格 | boolean | false |
| getRowId | 行 id 生成函数 | (row, index) => string | - |
| sorting (v-model) | 排序状态(受控;不传则内部维护) | SortingState | - |
| expanded (v-model) | 展开状态(受控;不传则内部维护) | ExpandedState | - |
| rowSelection (v-model) | 选中行(受控;不传则内部维护) | RowSelectionState | - |
| 事件 | 说明 | 回调参数 |
|---|
| update:sorting | 排序状态变化 | (sorting: SortingState) |
| update:expanded | 展开状态变化 | (expanded: ExpandedState) |
| update:rowSelection | 选中行变化 | (rowSelection) |
| rowClick | 点击数据行 | (row, event) |
TableColumn = TanStack ColumnDef + meta?: TableColumnMeta。
| meta | 说明 | 类型 |
|---|
class.th / class.td | 表头 / 单元格 class | string |
style.th / style.td | 表头 / 单元格 style | string |
colspan.th / colspan.td | 合并列 | number |
rowspan.td | 合并行 | number |
列结构不固定、或需要完全自定义单元格时,可用基础原子组件手写结构,无需 columns 与 TanStack。
TableRoot 即裸 <table> 容器(原 ui/table 的 Table),其余组件与原生 <table> 结构一一对应。
<script setup lang="ts">
import { TableRoot, TableHeader, TableBody, TableRow, TableHead, TableCell } from "@reglow/reui";
const rows = [
{ id: "4600", email: "james.anderson@example.com", amount: 594 },
{ id: "4599", email: "mia.white@example.com", amount: 276 },
];
</script>
<template>
<TableRoot>
<TableHeader>
<TableRow>
<TableHead>订单号</TableHead>
<TableHead>邮箱</TableHead>
<TableHead class="text-right">金额</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow v-for="row in rows" :key="row.id">
<TableCell class="font-medium">#{{ row.id }}</TableCell>
<TableCell>{{ row.email }}</TableCell>
<TableCell class="text-right">€{{ row.amount }}</TableCell>
</TableRow>
</TableBody>
</TableRoot>
</template>
旧的 @/components/ui/table 引用保持不变(该层已改为转发到 reui/table,其 Table 仍指 TableRoot)。
PageTable 是列表页专用的「特殊组件」:内部同样基于 TanStack Table,把搜索、分页、列管理、行操作、无限滚动、服务端排序等列表页固定套路一并封装。
<script setup lang="ts">
import { ref } from "vue";
import { PageTable } from "@reglow/reui";
import type { ColumnDef } from "@tanstack/vue-table";
interface User {
id: number;
name: string;
email: string;
}
const columns: ColumnDef<User>[] = [
{ accessorKey: "name", header: "姓名" },
{ accessorKey: "email", header: "邮箱" },
];
const data: User[] = [
{ id: 1, name: "张三", email: "zhang@example.com" },
{ id: 2, name: "李四", email: "li@example.com" },
];
const page = ref(1);
const pageSize = ref(20);
</script>
<template>
<PageTable
:columns="columns"
:data="data"
:total="100"
v-model:page="page"
v-model:page-size="pageSize"
:page-size-options="[10, 20, 50, 100]"
searchable
/>
</template>
通过 searchable、search-keys 开启搜索功能,使用 v-model:search 双向绑定搜索词。搜索框支持一键清空(allow-clear),清空后前端筛选立即恢复全量数据。
<script setup lang="ts">
import { ref } from "vue";
const search = ref("");
</script>
<template>
<PageTable
:columns="columns"
:data="data"
searchable
search-placeholder="搜索..."
v-model:search="search"
:search-keys="['name', 'email']"
/>
</template>
通过 selectable 开启行选择,使用 v-model:row-selection 双向绑定选中状态。
<script setup lang="ts">
import { ref } from "vue";
const rowSelection = ref({});
</script>
<template>
<PageTable
:columns="columns"
:data="data"
selectable
v-model:row-selection="rowSelection"
@row-selection-change="(val) => console.log(val)"
/>
</template>
通过 row-actions 配置行操作按钮,支持确认弹窗、样式变体等。
<script setup lang="ts">
import type { RowAction } from "@reglow/reui";
const rowActions: RowAction<User>[] = [
{
key: "edit",
label: "编辑",
onClick: (row) => console.log("编辑", row),
},
{
key: "delete",
label: "删除",
variant: "destructive",
confirm: { title: "确认删除?", description: "此操作不可撤销" },
onClick: (row) => console.log("删除", row),
},
];
</script>
<template>
<PageTable :columns="columns" :data="data" :row-actions="rowActions" />
</template>
未配置 row-actions 时,若列定义中存在自定义的 actions 列(如 id: "actions"),组件会回退渲染该列的 cell(此前只显示空文案)。
通过 loading 显示加载状态,loading-animation 控制动画样式。
<template>
<PageTable :columns="columns" :data="data" loading loading-animation="spin" />
</template>
无数据(且非加载中)时,表体展示内置插画 + 文案,文案默认取 i18n common.noData(暂无数据),可用 empty 覆盖,也可用 #empty 插槽完全替换。
<template>
<PageTable :columns="columns" :data="[]" empty="暂无订单" />
<!-- 完全自定义空态 -->
<PageTable :columns="columns" :data="[]">
<template #empty>
<div class="py-8">还没有订单,去创建第一单吧</div>
</template>
</PageTable>
</template>
通过 infinite-scroll 替代分页,配合 loading-more、has-more 和 load-more 事件。
<script setup lang="ts">
import { ref } from "vue";
const loadingMore = ref(false);
const hasMore = ref(true);
const onLoadMore = () => {
loadingMore.value = true;
// 加载更多
setTimeout(() => {
loadingMore.value = false;
}, 1000);
};
</script>
<template>
<PageTable
:columns="columns"
:data="data"
infinite-scroll
:loading-more="loadingMore"
:has-more="hasMore"
@load-more="onLoadMore"
/>
</template>
用户可通过列管理按钮控制列的显示/隐藏,支持拖拽排序。
<template>
<PageTable :columns="columns" :data="data" />
</template>
默认排序是本地排序:对当前页已加载的数据排序,翻页后排序不跨页。
需要按整表排序时,传入 manual-sorting 并配合 v-model:sorting:组件不再做本地排序,
点击表头只更新 / 上报排序状态,由父组件带排序参数重新请求。
<script setup lang="ts">
import { computed, ref } from "vue";
import type { ColumnDef, SortingState } from "@tanstack/vue-table";
const columns: ColumnDef<User>[] = [
{ accessorKey: "name", header: "姓名" },
{ accessorKey: "email", header: "邮箱" },
];
const page = ref(1);
const pageSize = ref(20);
const sorting = ref<SortingState>([]);
const list = ref<User[]>([]);
const total = ref(0);
async function load() {
const s = sorting.value[0];
const res = await userApi.list({
page: page.value,
size: pageSize.value,
// 列的 id(accessorKey / id)需与接口字段名一致,如 created_at
sort_by: s?.id,
sort_order: s ? (s.desc ? "desc" : "asc") : undefined,
});
list.value = res.data.items;
total.value = res.data.total;
}
// 排序变化后回到第 1 页再请求
function onSortChange() {
page.value = 1;
load();
}
</script>
<template>
<PageTable
v-model:sorting="sorting"
manual-sorting
:columns="columns"
:data="list"
:total="total"
v-model:page="page"
v-model:page-size="pageSize"
@sort-change="onSortChange"
/>
</template>
服务端约定(@reglow/design 内置的四个后端实现一致):
| 参数 | 说明 |
|---|
sort_by | 排序字段名,取列表项 DTO 的 snake_case 字段名(如 created_at、nickname),需在该接口可排序白名单内 |
sort_order | asc / desc,大小写不敏感,默认 asc |
- 字段名非法或不在白名单时,服务端忽略排序参数并回落该接口默认排序(不报错、不返回 400)。
- 排序生效时,次排序为该接口原有默认排序,保证分页结果稳定。
- 只需禁止某列排序时,在该列定义上设
enableSorting: false。
默认是单列排序:点表头只保留当前列(Shift + 点击也一样)。传入 multi-sort 后,按住 Shift 点击可累加多列,
普通点击仍只保留当前列;存在多列排序时表头会显示优先级序号(1、2、3…)。
<template>
<PageTable
v-model:sorting="sorting"
manual-sorting
multi-sort
:columns="columns"
:data="list"
:total="total"
@sort-change="onSortChange"
/>
</template>
请求参数由 toSortParams(sorting) 生成:多列时拼成 sort_by=nickname:asc,created_at:desc;单列时仍是 sort_by=created_at&sort_order=desc。
注意事项:
- 顺序即优先级:
sort_by=a:desc,b:asc = 先按 a 降序,a 相同时再按 b 升序;最后仍会追加服务端该接口的默认排序作为兜底,保证分页稳定。 - 最多 3 列:组件与服务端都限制为 3 列,第 4 列起不再累加(四端后端一致)。
- 逐列校验:字段不在该接口可排序白名单内(或属敏感列)时,只跳过该列,其余列照常生效;若一列都不合法,则整体回落该接口默认排序,不报错。
- 列 id 必须与服务端字段名一致(通常就是
accessorKey 的 snake_case 列名),否则该列会被服务端忽略——表现为「点什么都没反应」。 - 单列时行为与未开启该开关时完全一致;
multi-sort 只在组件层控制能否累加,服务端是否支持多列取决于接口(@reglow/design 内置的四个后端已支持)。 - 本地排序模式(未传
manual-sorting)下同样可用:多列排序由 TanStack 在当前页数据上依次应用。
为每行提供一段可展开的补充内容:传入 render-expanded-row(返回 VNode),或使用 #expanded="{ row, tableRow }" 插槽。
展开状态可用 v-model:expanded 受控,也可通过 @expand-change 监听。
<script setup lang="ts">
import { h } from "vue";
import type { ColumnDef } from "@tanstack/vue-table";
interface Order {
id: number;
no: string;
customer: string;
amount: number;
}
const columns: ColumnDef<Order>[] = [
{ accessorKey: "no", header: "订单号" },
{ accessorKey: "customer", header: "客户" },
{ accessorKey: "amount", header: "金额" },
];
function renderExpanded(row: Order) {
return h(
"div",
{ class: "px-4 py-3 text-sm" },
`订单 ${row.no} · ¥${row.amount}`,
);
}
</script>
<template>
<PageTable
:columns="columns"
:data="data"
:total="data.length"
row-key="id"
:render-expanded-row="renderExpanded"
/>
</template>
插槽写法(适合放更复杂的模板):
<template>
<PageTable :columns="columns" :data="data" :total="data.length" row-key="id">
<template #expanded="{ row }">
<div class="px-4 py-3 text-sm">订单 {{ row.no }} · ¥{{ row.amount }}</div>
</template>
</PageTable>
</template>
传入 tree 开启树表:组件按 children-key(默认 children)递归渲染层级,首列显示展开箭头,并按 indent-size(默认 16px)逐级缩进。
建议同时传 row-key(行唯一字段名),让展开状态在分页 / 刷新后保持一致;default-expand-all 可初始展开全部层级。
<script setup lang="ts">
import type { ColumnDef } from "@tanstack/vue-table";
interface Dept {
id: number;
name: string;
owner: string;
children?: Dept[];
}
const columns: ColumnDef<Dept>[] = [
{ accessorKey: "name", header: "组织名称" },
{ accessorKey: "owner", header: "负责人" },
];
</script>
<template>
<PageTable
:columns="columns"
:data="data"
:total="data.length"
tree
row-key="id"
default-expand-all
/>
</template>
树表的子行是客户端数据:data 需包含嵌套子节点(字段名可用 children-key 调整);服务端分页时通常只对顶层分页。
需要树表 + 服务端数据时,可让接口返回当前页的树形结构,展开状态由前端维护。
| 属性 | 类型 | 默认值 | 说明 |
|---|
columns | ColumnDef[] | - | 列定义(TanStack Table) |
data | TData[] | - | 数据 |
total | number | 0 | 总条数 |
page | number | 1 | 当前页(v-model) |
pageSize | number | 20 | 每页条数(v-model) |
loading | boolean | false | 加载中 |
loadingColor | string | currentColor | 加载颜色 |
loadingAnimation | "spin" | "pulse" | "bounce" | "spin" | 加载动画 |
searchable | boolean | true | 可搜索 |
searchPlaceholder | string | - | 搜索占位 |
searchKeys | string[] | - | 搜索字段 |
search | string | - | 搜索词(v-model) |
selectable | boolean | false | 可选择行 |
rowSelection | RowSelectionState | - | 选中行(v-model) |
sorting | SortingState | - | 排序状态(受控;不传则组件内部维护) |
manualSorting | boolean | false | 服务端排序:不做本地排序,仅上报排序状态 |
multiSort | boolean | false | 允许多列排序(Shift + 点击累加,显示优先级序号) |
rowActions | RowAction[] | - | 行操作 |
empty | string | i18n common.noData | 空数据文案 |
pageSizeOptions | number[] | [10, 20, 50, 100] | 每页选项 |
infiniteScroll | boolean | false | 无限滚动 |
loadingMore | boolean | false | 加载更多中 |
hasMore | boolean | false | 有更多数据 |
rowClass | (row) => string | - | 行 class |
buttonPermissionMode | "hide" | "disable" | 全局配置 | 无权限行操作的展示方式 |
expanded | ExpandedState | - | 展开状态(v-model:expanded;不传则组件内部维护) |
tree | boolean | false | 树表模式:按 childrenKey 递归渲染层级 |
childrenKey | string | "children" | 树表子节点字段名 |
defaultExpandAll | boolean | false | 树表 / 可展开行:初始全部展开 |
indentSize | number | 16 | 树表每级缩进(px) |
rowKey | string | - | 行唯一键字段名(稳定展开 / 选中状态) |
renderExpandedRow | (row, tableRow) => VNode | - | 可展开行的内容 |
| 事件 | 说明 | 回调参数 |
|---|
update:page | 页码变化 | (page: number) |
update:pageSize | 每页条数变化 | (pageSize: number) |
update:search | 搜索变化 | (search: string) |
update:rowSelection | 选择变化 | (rowSelection) |
update:sorting | 排序状态变化(v-model:sorting) | (sorting: SortingState) |
rowSelectionChange | 选择变化 | (rowSelection) |
sortChange | 点击表头排序变化(服务端排序时据此重新请求) | (sorting: SortingState) |
loadMore | 加载更多 | () |
update:expanded | 展开状态变化(v-model:expanded) | (expanded: ExpandedState) |
expandChange | 展开状态变化 | (expanded: ExpandedState) |
| 插槽 | 说明 |
|---|
filters-after | 搜索区之后(可用于放置刷新等自定义操作) |
empty | 空数据(完全替换内置的插画 + 文案空态) |
| 属性 | 类型 | 默认值 | 说明 |
|---|
key | string | - | 唯一标识 |
label | string | - | 显示文字 |
icon | any | - | 图标 |
variant | "default" | "destructive" | "outline" | "ghost" | "default" | 样式 |
show | (row) => boolean | - | 是否显示 |
confirm | { title, description? } | - | 确认弹窗 |
tooltip | string | - | 提示 |
onClick | (row) => void | - | 点击回调 |