Table 表格

基于 TanStack Table 的通用表格与分页表格,支持自动列、排序、行选择、展开行、搜索、分页、列管理与服务端排序

本目录提供两个组件,共用同一套列定义(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 的插槽打底。

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>

tableApi(深度定制)

组件 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>

Table API

Table Props

参数说明类型默认值
data表格数据TData[][]
columns列定义;不传时按首行 key 自动生成TableColumn[]-
caption表格标题string-
empty空数据文案stringi18n common.noData
meta表格级 meta(class.tr)TableMetaConfig-
sticky吸顶boolean | "header" | "footer"false
loading加载中booleanfalse
loadingColor加载条颜色stringcurrentColor
loadingAnimation加载条动画carousel | carousel-inverse | pulsecarousel
size行密度sm | md | lgmd
striped斑马纹booleanfalse
bordered边框网格booleanfalse
getRowId行 id 生成函数(row, index) => string-
sorting (v-model)排序状态(受控;不传则内部维护)SortingState-
expanded (v-model)展开状态(受控;不传则内部维护)ExpandedState-
rowSelection (v-model)选中行(受控;不传则内部维护)RowSelectionState-

Table Events

事件说明回调参数
update:sorting排序状态变化(sorting: SortingState)
update:expanded展开状态变化(expanded: ExpandedState)
update:rowSelection选中行变化(rowSelection)
rowClick点击数据行(row, event)

Table Expose

名称类型
tableApiTanStack Table

TableColumn / TableColumnMeta

TableColumn = TanStack ColumnDef + meta?: TableColumnMeta。

meta说明类型
class.th / class.td表头 / 单元格 classstring
style.th / style.td表头 / 单元格 stylestring
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 分页表格

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_orderasc / 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 在当前页数据上依次应用。

可展开行(expandable)

为每行提供一段可展开的补充内容:传入 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)

传入 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 调整);服务端分页时通常只对顶层分页。 需要树表 + 服务端数据时,可让接口返回当前页的树形结构,展开状态由前端维护。

PageTable API

PageTable Props

属性类型默认值说明
columnsColumnDef[]-列定义(TanStack Table)
dataTData[]-数据
totalnumber0总条数
pagenumber1当前页(v-model)
pageSizenumber20每页条数(v-model)
loadingbooleanfalse加载中
loadingColorstringcurrentColor加载颜色
loadingAnimation"spin" | "pulse" | "bounce""spin"加载动画
searchablebooleantrue可搜索
searchPlaceholderstring-搜索占位
searchKeysstring[]-搜索字段
searchstring-搜索词(v-model)
selectablebooleanfalse可选择行
rowSelectionRowSelectionState-选中行(v-model)
sortingSortingState-排序状态(受控;不传则组件内部维护)
manualSortingbooleanfalse服务端排序:不做本地排序,仅上报排序状态
multiSortbooleanfalse允许多列排序(Shift + 点击累加,显示优先级序号)
rowActionsRowAction[]-行操作
emptystringi18n common.noData空数据文案
pageSizeOptionsnumber[][10, 20, 50, 100]每页选项
infiniteScrollbooleanfalse无限滚动
loadingMorebooleanfalse加载更多中
hasMorebooleanfalse有更多数据
rowClass(row) => string-行 class
buttonPermissionMode"hide" | "disable"全局配置无权限行操作的展示方式
expandedExpandedState-展开状态(v-model:expanded;不传则组件内部维护)
treebooleanfalse树表模式:按 childrenKey 递归渲染层级
childrenKeystring"children"树表子节点字段名
defaultExpandAllbooleanfalse树表 / 可展开行:初始全部展开
indentSizenumber16树表每级缩进(px)
rowKeystring-行唯一键字段名(稳定展开 / 选中状态)
renderExpandedRow(row, tableRow) => VNode-可展开行的内容

PageTable Events

事件说明回调参数
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)

PageTable Slots

插槽说明
filters-after搜索区之后(可用于放置刷新等自定义操作)
empty空数据(完全替换内置的插画 + 文案空态)

RowAction

属性类型默认值说明
keystring-唯一标识
labelstring-显示文字
iconany-图标
variant"default" | "destructive" | "outline" | "ghost""default"样式
show(row) => boolean-是否显示
confirm{ title, description? }-确认弹窗
tooltipstring-提示
onClick(row) => void-点击回调