Skip to content

Table 表格

Table 组件用于展示结构化数据,默认支持分页。当 total > 0 时会自动显示分页;也可以通过传入 showPagination 强制显示分页。

基础用法

  • 显式开启分页(total=0 时仍显示):

    ID 姓名 年龄 地址
    1张伟22北京市朝阳区中关村大街1号
    2李秀英静23上海市海淀区建国门外大街1号
    3王丽24广州市西城区王府井大街1号
    4刘军涛25深圳市东城区西单北大街1号
    5陈艳26杭州市丰台区东单北大街1号
    6杨涛华27成都市石景山区复兴路1号
    7赵秀兰28武汉市通州区长安街1号
    8黄刚桂芬29西安市昌平区三环路1号
    9周文30南京市大兴区四环路1号
    10吴红静31重庆市房山区五环路1号
    总条数
  • 自定义分页文案与页大小:

    ID 姓名 年龄 地址
    1张伟22北京市朝阳区中关村大街1号
    2李秀英静23上海市海淀区建国门外大街1号
    3王丽24广州市西城区王府井大街1号
    4刘军涛25深圳市东城区西单北大街1号
    5陈艳26杭州市丰台区东单北大街1号
    6杨涛华27成都市石景山区复兴路1号
    7赵秀兰28武汉市通州区长安街1号
    8黄刚桂芬29西安市昌平区三环路1号
    9周文30南京市大兴区四环路1号
    10吴红静31重庆市房山区五环路1号
    共 35 条
  • 空数据与占位文案:

    ID 姓名 年龄 地址
    暂无数据
  • 自定义列宽与对齐:

    ID 姓名 分数
    1张伟94
    2李秀英静63
    3王丽84
    4刘军涛70
    5陈艳71
    6杨涛华80
    7赵秀兰85
    8黄刚桂芬60
    总条数
  • 使用 rowKey

    唯一键 姓名
    row-1763545355052-0张伟
    row-1763545355052-1李秀英静
    row-1763545355052-2王丽
    row-1763545355052-3刘军涛
    row-1763545355052-4陈艳
    总条数
  • 不同尺寸:

    ID 姓名
    1张伟
    2李秀英静
    3王丽
    4刘军涛
    5陈艳
    6杨涛华
    总条数
    ID 姓名
    1张伟
    2李秀英静
    3王丽
    4刘军涛
    5陈艳
    6杨涛华
    总条数
    ID 姓名
    1张伟
    2李秀英静
    3王丽
    4刘军涛
    5陈艳
    6杨涛华
    总条数
  • 列宽拖拽:

    ID 姓名 年龄 地址 ID 姓名 年龄 地址
    1张伟22北京市朝阳区中关村大街1号1张伟22北京市朝阳区中关村大街1号
    2李秀英静23上海市海淀区建国门外大街1号2李秀英静23上海市海淀区建国门外大街1号
    3王丽24广州市西城区王府井大街1号3王丽24广州市西城区王府井大街1号
    4刘军涛25深圳市东城区西单北大街1号4刘军涛25深圳市东城区西单北大街1号
    5陈艳26杭州市丰台区东单北大街1号5陈艳26杭州市丰台区东单北大街1号
    6杨涛华27成都市石景山区复兴路1号6杨涛华27成都市石景山区复兴路1号
    7赵秀兰28武汉市通州区长安街1号7赵秀兰28武汉市通州区长安街1号
    8黄刚桂芬29西安市昌平区三环路1号8黄刚桂芬29西安市昌平区三环路1号
    9周文30南京市大兴区四环路1号9周文30南京市大兴区四环路1号
    10吴红静31重庆市房山区五环路1号10吴红静31重庆市房山区五环路1号
    总条数

    提示:将鼠标移动到表头最右侧,即可拖拽调整列宽。

  • 自定义单元格插槽(操作列):

    ID 姓名 年龄 操作
    1张伟22
    2李秀英静23
    3王丽24
    4刘军涛25
    5陈艳26
    6杨涛华27
    7赵秀兰28
    8黄刚桂芬29
    9周文30
    10吴红静31
    总条数
  • 使用子组件定义列(Element Plus 风格):

    总条数
  • 事件用法示例(监听 pageChange):

    ID 姓名 年龄 地址
    1张伟22北京市朝阳区中关村大街1号
    2李秀英静23上海市海淀区建国门外大街1号
    3王丽24广州市西城区王府井大街1号
    4刘军涛25深圳市东城区西单北大街1号
    5陈艳26杭州市丰台区东单北大街1号
    6杨涛华27成都市石景山区复兴路1号
    7赵秀兰28武汉市通州区长安街1号
    8黄刚桂芬29西安市昌平区三环路1号
    9周文30南京市大兴区四环路1号
    10吴红静31重庆市房山区五环路1号
    总条数
  • 服务端分页(模拟请求):

    ID 姓名 年龄 地址
    暂无数据
    总条数
  • 动态列显示/隐藏:

    ID 姓名 年龄 地址 ID 姓名 年龄 地址
    1张伟22北京市朝阳区中关村大街1号1张伟22北京市朝阳区中关村大街1号
    2李秀英静23上海市海淀区建国门外大街1号2李秀英静23上海市海淀区建国门外大街1号
    3王丽24广州市西城区王府井大街1号3王丽24广州市西城区王府井大街1号
    4刘军涛25深圳市东城区西单北大街1号4刘军涛25深圳市东城区西单北大街1号
    5陈艳26杭州市丰台区东单北大街1号5陈艳26杭州市丰台区东单北大街1号
    6杨涛华27成都市石景山区复兴路1号6杨涛华27成都市石景山区复兴路1号
    7赵秀兰28武汉市通州区长安街1号7赵秀兰28武汉市通州区长安街1号
    8黄刚桂芬29西安市昌平区三环路1号8黄刚桂芬29西安市昌平区三环路1号
    9周文30南京市大兴区四环路1号9周文30南京市大兴区四环路1号
    10吴红静31重庆市房山区五环路1号10吴红静31重庆市房山区五环路1号
    总条数
  • 固定表头与横向滚动:

    ID 姓名 部门 职位 邮箱 地址
    1张伟技术部前端工程师user00@example.com北京市朝阳区中关村大街1号
    2李秀英静产品部后端工程师user11@example.com上海市海淀区建国门外大街1号
    3王丽设计部产品经理user22@example.com广州市西城区王府井大街1号
    4刘军涛运营部UI设计师user33@example.com深圳市东城区西单北大街1号
    5陈艳市场部运营专员user44@example.com杭州市丰台区东单北大街1号
    6杨涛华财务部市场专员user55@example.com成都市石景山区复兴路1号
    7赵秀兰人事部财务专员user66@example.com武汉市通州区长安街1号
    8黄刚桂芬行政部人事专员user77@example.com西安市昌平区三环路1号
    9周文技术部前端工程师user88@example.com南京市大兴区四环路1号
    10吴红静产品部后端工程师user99@example.com重庆市房山区五环路1号
    总条数
  • 横向滚动(内置属性 scrollX):

    ID 姓名 部门 职位 邮箱 地址 城市 省份 邮编
    1张伟技术部前端工程师user00@example.com北京市朝阳区中关村大街1号北京市北京市100000
    2李秀英静产品部后端工程师user11@example.com上海市海淀区建国门外大街1号上海市上海市100001
    3王丽设计部产品经理user22@example.com广州市西城区王府井大街1号广州市广东省100002
    4刘军涛运营部UI设计师user33@example.com深圳市东城区西单北大街1号深圳市浙江省100003
    5陈艳市场部运营专员user44@example.com杭州市丰台区东单北大街1号杭州市江苏省100004
    6杨涛华财务部市场专员user55@example.com成都市石景山区复兴路1号成都市四川省100005
    7赵秀兰人事部财务专员user66@example.com武汉市通州区长安街1号武汉市湖北省100006
    8黄刚桂芬行政部人事专员user77@example.com西安市昌平区三环路1号西安市陕西省100007
    9周文技术部前端工程师user88@example.com南京市大兴区四环路1号南京市河南省100008
    10吴红静产品部后端工程师user99@example.com重庆市房山区五环路1号重庆市山东省100009
    总条数

基础用法代码示例

vue
<script setup lang="ts">
import { ref } from 'vue'

const columns = [
  { key: 'id', title: 'ID', width: 80 },
  { key: 'name', title: '名称' },
  { key: 'age', title: '年龄', align: 'center', width: 100 },
  { key: 'address', title: '地址' }
]

// 模拟数据生成辅助函数
const surnames = ['张', '李', '王', '刘', '陈', '杨', '赵', '黄', '周', '吴']
const givenNames = ['伟', '芳', '娜', '敏', '静', '丽', '强', '磊', '军', '洋']
const cities = [
  '北京市',
  '上海市',
  '广州市',
  '深圳市',
  '杭州市',
  '成都市',
  '武汉市',
  '西安市',
  '南京市',
  '重庆市'
]
const districts = ['朝阳区', '海淀区', '西城区', '东城区', '丰台区']
const streets = [
  '中关村大街',
  '建国门外大街',
  '王府井大街',
  '西单北大街',
  '东单北大街'
]

function generateName(index: number) {
  const surname = surnames[index % surnames.length]
  const givenName =
    givenNames[(index * 3) % givenNames.length] +
    (index % 2 === 0 ? '' : givenNames[(index * 5) % givenNames.length])
  return surname + givenName
}

function generateAddress(index: number) {
  const city = cities[index % cities.length]
  const district = districts[index % districts.length]
  const street = streets[index % streets.length]
  const number = Math.floor(index / 10) + 1
  return `${city}${district}${street}${number}号`
}

const data = Array.from({ length: 35 }).map((_, i) => ({
  id: i + 1,
  name: generateName(i),
  age: 22 + (i % 24),
  address: generateAddress(i)
}))

const currentPage = ref(1)
const pageSize = ref(10)
</script>

<template>
  <c-table
    :columns="columns"
    :data="data"
    :total="data.length"
    v-model:currentPage="currentPage"
    v-model:pageSize="pageSize"
  />
</template>

自定义列宽与对齐

通过在 columns 中设置 widthalign 可控制列的宽度与文字对齐方式。

vue
<script setup lang="ts">
const alignColumns = [
  { key: 'id', title: 'ID', width: 80, align: 'center' },
  { key: 'name', title: '名称', width: 160 },
  { key: 'score', title: '分数', align: 'right', width: 100 }
]

const alignData = Array.from({ length: 8 }).map((_, i) => ({
  id: i + 1,
  name: generateName(i),
  score: Math.round(60 + Math.random() * 40)
}))
</script>

<template>
  <c-table
    :columns="alignColumns"
    :data="alignData"
    :total="alignData.length"
  />
  <!-- 可强制显示分页(示例:total 为 0 但仍显示) -->
  <c-table
    :columns="alignColumns"
    :data="alignData"
    :total="0"
    :show-pagination="true"
  />
  <!-- 仅设置列宽,不设置分页 -->
  <c-table :columns="alignColumns" :data="alignData" :total="0" />
</template>

使用 rowKey

当数据项不使用默认的 id 字段作为唯一标识时,可通过 rowKey 指定唯一键字段,提升列表渲染稳定性。

vue
<script setup lang="ts">
const uuidColumns = [
  { key: 'uuid', title: '唯一键', width: 220 },
  { key: 'name', title: '名称' }
]

const uuidData = Array.from({ length: 5 }).map((_, i) => ({
  uuid: `row-${Date.now()}-${i}`,
  name: generateName(i)
}))
</script>

<template>
  <c-table
    :columns="uuidColumns"
    :data="uuidData"
    :total="uuidData.length"
    row-key="uuid"
  />
</template>

不同尺寸

通过 size 控制表格的整体视觉密度,提供 small | medium | large 三种尺寸。

vue
<script setup lang="ts">
const sizeColumns = [
  { key: 'id', title: 'ID', width: 80 },
  { key: 'name', title: '名称' }
]

const sizeData = Array.from({ length: 6 }).map((_, i) => ({
  id: i + 1,
  name: generateName(i)
}))
</script>

<template>
  <div class="table-size-demo">
    <c-table
      size="small"
      :columns="sizeColumns"
      :data="sizeData"
      :total="sizeData.length"
    />
    <c-table
      size="medium"
      :columns="sizeColumns"
      :data="sizeData"
      :total="sizeData.length"
    />
    <c-table
      size="large"
      :columns="sizeColumns"
      :data="sizeData"
      :total="sizeData.length"
    />
  </div>
</template>

<style>
.table-size-demo .c-table + .c-table {
  margin-top: 16px;
}
</style>

列宽拖拽

通过为组件传入 columnResizable 开启列宽拖拽,支持通过 minColumnWidthmaxColumnWidth 限制拖拽范围(单位:px)。当前版本仅支持像素宽度的列拖拽(不支持百分比宽度)。

vue
<script setup lang="ts">
const dragColumns = [
  { key: 'id', title: 'ID', align: 'center' },
  { key: 'name', title: '名称' },
  { key: 'age', title: '年龄', align: 'center' },
  { key: 'address', title: '地址' },
  { key: 'id', title: 'ID', align: 'center' },
  { key: 'name', title: '名称' },
  { key: 'age', title: '年龄', align: 'center' },
  { key: 'address', title: '地址' },
  { key: 'id', title: 'ID', align: 'center' },
  { key: 'name', title: '名称' },
  { key: 'age', title: '年龄', align: 'center' },
  { key: 'address', title: '地址' }
]

const dragData = Array.from({ length: 12 }).map((_, i) => ({
  id: i + 1,
  name: generateName(i),
  age: 22 + (i % 24),
  address: generateAddress(i)
}))
</script>

<template>
  <c-table
    :columns="dragColumns"
    :data="dragData"
    :total="dragData.length"
    column-resizable
    :min-column-width="80"
    :max-column-width="500"
  />
  <p class="tip">提示:将鼠标移动到表头最右侧,即可拖拽调整列宽。</p>
</template>

自定义单元格插槽(操作列)

每列会自动以其 key 作为插槽名称。可通过具名插槽自定义单元格内容,例如添加操作按钮或富文本内容。

vue
<script setup lang="ts">
import { ref } from 'vue'

const actionColumns = [
  { key: 'id', title: 'ID', width: 80, align: 'center' },
  { key: 'name', title: '名称' },
  { key: 'age', title: '年龄', width: 100, align: 'center' },
  { key: 'actions', title: '操作', width: 220, align: 'center' }
]

const actionData = ref(Array.from({ length: 12 }).map((_, i) => ({
  id: i + 1,
  name: generateName(i),
  age: 22 + (i % 24),
  actions: ''
})))

function onView(row: any) {
  console.log('查看:', row)
}
function onEdit(row: any) {
  console.log('编辑:', row)
}
function onDelete(row: any) {
  console.log('删除:', row)
  actionData.value = actionData.value.filter(r => r.id !== row.id)
}
</script>

<template>
  <div class="table-demo">
    <c-table
      :columns="actionColumns"
      :data="actionData"
      :total="actionData.length"
      :page-sizes="[5, 10, 20]"
      v-model:currentPage="currentPage"
      v-model:pageSize="pageSize"
    >
      <!-- 自定义名称列:加粗显示 -->
      <template #name="{ row }">
        <strong>{{ row.name }}</strong>
      </template>

      <!-- 自定义操作列:按钮组 -->
      <template #actions="{ row }">
        <c-button size="small" type="primary" class="action-btn" @click="onView(row)">查看</c-button>
        <c-button size="small" type="warning" class="action-btn" @click="onEdit(row)">编辑</c-button>
        <c-button size="small" type="danger" plain class="action-btn" @click="onDelete(row)">删除</c-button>
      </template>
    </c-table>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
const currentPage = ref(1)
const pageSize = ref(10)
</script>

<style>
.table-demo .action-btn + .action-btn {
  margin-left: 8px;
}
</style>

Props

属性名说明类型可选值默认值
columns列定义Array<{ key: string; title: string; width?: number; align?: 'left' | 'center' | 'right' }>align: left / center / right
data表格数据Array<Record<string, any>>
total数据总条数,用于分页显示与计算number
currentPage当前页(支持 v-model:currentPage)number
pageSize每页数量(支持 v-model:pageSize)number
showPagination是否显示分页(即使 total 为 0)booleanfalse
pageSizes可选页大小列表number[]
showSizeChanger是否显示页大小切换器boolean
showTotal是否显示总条数文案boolean
totalText总条数字符串模板,支持 {total} 占位符string
emptyText空数据占位文案string
rowKey行唯一键(用于提升渲染效率)string
size表格尺寸'small' | 'medium' | 'large'small / medium / largemedium
columnResizable是否开启列宽拖拽booleanfalse
minColumnWidth最小列宽(px)number60
maxColumnWidth最大列宽(px)number600
scrollX是否启用横向滚动。开启后内部表格 min-width 等于所有列宽总和,可出现横向滚动条。booleantrue
height表格可视高度。超过该高度时仅内容区(tbody)滚动,表头默认固定。number | string300px
stickyHeader是否固定表头。固定后,垂直滚动仅发生在内容区,表头保持不动。booleantrue

Emits

  • update:currentPage 当前页变更
  • update:pageSize 页大小变更
  • pageChange 分页变化(包含当前页与页大小)

事件用法示例

在表格上监听 pageChange(或 update:currentPage / update:pageSize)以处理分页变化。

vue
<script setup lang="ts">
import { ref } from 'vue'

const columns = [
  { key: 'id', title: 'ID', width: 80, align: 'center' },
  { key: 'name', title: '名称' },
  { key: 'age', title: '年龄', width: 100, align: 'center' }
]

const allData = Array.from({ length: 50 }).map((_, i) => ({
  id: i + 1,
  name: generateName(i),
  age: 22 + (i % 24)
}))

const currentPage = ref(1)
const pageSize = ref(10)

function onPageChange(page: number, size: number) {
  console.log('分页变化', { page, size })
}
</script>

<template>
  <c-table
    :columns="columns"
    :data="allData"
    :total="allData.length"
    v-model:currentPage="currentPage"
    v-model:pageSize="pageSize"
    @pageChange="onPageChange"
  />
  <!-- 等价:
  <c-table
    ...
    @update:currentPage="(p)=>currentPage=p"
    @update:pageSize="(s)=>pageSize=s"
  />
  -->
</template>

服务端分页(示例)

通过监听 pageChange,请求服务端接口加载当前页数据,并更新 datatotal

vue
<script setup lang="ts">
import { ref } from 'vue'

const columns = [
  { key: 'id', title: 'ID', width: 80, align: 'center' },
  { key: 'name', title: '名称' },
  { key: 'age', title: '年龄', width: 100, align: 'center' }
]

const data = ref<any[]>([])
const total = ref(0)
const currentPage = ref(1)
const pageSize = ref(10)

async function fetchList(page: number, size: number) {
  // 示例:模拟请求,可替换为真实接口
  await new Promise((r) => setTimeout(r, 300))
  const mockTotal = 123
  const start = (page - 1) * size
  const pageData = Array.from({ length: size }).map((_, i) => ({
    id: start + i + 1,
    name: generateName(start + i),
    age: 22 + ((start + i) % 24),
    address: generateAddress(start + i)
  }))
  data.value = pageData
  total.value = mockTotal
}

function onPageChange(page: number, size: number) {
  fetchList(page, size)
}

// 初始化加载
fetchList(currentPage.value, pageSize.value)
</script>

<template>
  <c-table
    :columns="columns"
    :data="data"
    :total="total"
    v-model:currentPage="currentPage"
    v-model:pageSize="pageSize"
    @pageChange="onPageChange"
    :show-pagination="true"
  />
</template>

最佳实践

  • 设置 rowKey,确保每行有稳定唯一键,提升渲染稳定性。
  • 需要列宽拖拽时,为列设置像素宽度(如 80"120px")。
  • 大量自定义插槽时,尽量减少复杂计算或频繁状态更新,避免性能问题。
  • 分页与数据请求分离:通过 pageChange 驱动请求,响应后更新 datatotal

常见问题

  • 为什么列宽拖拽不生效?拖拽仅支持像素宽度,百分比或自适应宽度无法拖拽。
  • total 为 0 时分页不显示?可以通过 showPagination 强制显示。
  • 列对齐不生效?检查列定义中的 align 是否设置为 left|center|right

动态列显示/隐藏

通过维护可见列的 key 列表,动态计算传入的 columns

vue
<script setup lang="ts">
import { ref, computed } from 'vue'

const baseColumns = [
  { key: 'id', title: 'ID', width: 80, align: 'center' },
  { key: 'name', title: '名称', width: 160 },
  { key: 'age', title: '年龄', width: 100, align: 'center' },
  { key: 'address', title: '地址', width: 240 }
]

const visibleKeys = ref<string[]>(baseColumns.map((c) => c.key))
const columnsDyn = computed(() =>
  baseColumns.filter((c) => visibleKeys.value.includes(c.key))
)

function onToggle(key: string, checked: boolean) {
  const set = new Set(visibleKeys.value)
  if (checked) set.add(key)
  else set.delete(key)
  visibleKeys.value = Array.from(set)
}

const dataDyn = Array.from({ length: 12 }).map((_, i) => ({
  id: i + 1,
  name: generateName(i),
  age: 22 + (i % 24),
  address: generateAddress(i)
}))
</script>

<template>
  <div class="table-dynamic">
    <div class="controls">
      <label v-for="c in baseColumns" :key="c.key">
        <input
          type="checkbox"
          :checked="visibleKeys.includes(c.key)"
          @change="onToggle(c.key, ($event.target as HTMLInputElement).checked)"
        />
        {{ c.title }}
      </label>
    </div>
    <c-table :columns="columnsDyn" :data="dataDyn" :total="dataDyn.length" />
  </div>
</template>

<style>
.table-dynamic .controls {
  margin-bottom: 8px;
}
.table-dynamic .controls label {
  margin-right: 12px;
}
</style>

固定表头与横向滚动

使用容器滚动,结合 position: sticky 固定表头。横向滚动通过设置较宽的列总宽度触发。

vue
<script setup lang="ts">
const wideColumns = [
  { key: 'id', title: 'ID', width: 100, align: 'center' },
  { key: 'name', title: '名称', width: 240 },
  { key: 'dept', title: '部门', width: 240 },
  { key: 'role', title: '角色', width: 240 },
  { key: 'email', title: '邮箱', width: 300 },
  { key: 'address', title: '地址', width: 360 }
]

const departments = [
  '技术部',
  '产品部',
  '设计部',
  '运营部',
  '市场部',
  '财务部',
  '人事部',
  '行政部'
]
const roles = [
  '前端工程师',
  '后端工程师',
  '产品经理',
  'UI设计师',
  '运营专员',
  '市场专员',
  '财务专员',
  '人事专员'
]

function generateEmail(name: string, index: number) {
  const pinyin = name.toLowerCase().replace(/[^a-z]/g, '') || `user${index}`
  return `${pinyin}${index}@example.com`
}

const wideData = Array.from({ length: 30 }).map((_, i) => {
  const name = generateName(i)
  return {
    id: i + 1,
    name,
    dept: departments[i % departments.length],
    role: roles[i % roles.length],
    email: generateEmail(name, i),
    address: generateAddress(i)
  }
})

// 内置横向滚动示例:列更多、总宽更大
const wideColumns2 = [
  { key: 'id', title: 'ID', width: 100, align: 'center' },
  { key: 'name', title: '名称', width: 240 },
  { key: 'dept', title: '部门', width: 240 },
  { key: 'role', title: '角色', width: 240 },
  { key: 'email', title: '邮箱', width: 300 },
  { key: 'address', title: '地址', width: 360 },
  { key: 'city', title: '城市', width: 240 },
  { key: 'country', title: '国家', width: 240 },
  { key: 'zip', title: '邮编', width: 200 }
]
const provinces = [
  '北京市',
  '上海市',
  '广东省',
  '浙江省',
  '江苏省',
  '四川省',
  '湖北省',
  '陕西省',
  '河南省',
  '山东省'
]
const wideData2 = Array.from({ length: 30 }).map((_, i) => {
  const name = generateName(i)
  const city = cities[i % cities.length]
  return {
    id: i + 1,
    name,
    dept: departments[i % departments.length],
    role: roles[i % roles.length],
    email: generateEmail(name, i),
    address: generateAddress(i),
    city,
    province: provinces[i % provinces.length],
    zip: `${100000 + (i % 10000)}`
  }
})
</script>

<template>
  <div class="table-sticky-scroll">
    <c-table :columns="wideColumns" :data="wideData" :total="wideData.length" />
  </div>
</template>

<style>
.table-sticky-scroll {
  max-height: 220px;
  overflow: auto;
  border: 1px solid #ebeef5;
}
.table-sticky-scroll .c-table__inner {
  min-width: 1200px;
}
.table-sticky-scroll thead .c-table__th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: #f8f9fb;
}
</style>

类型参考与大数据量建议

ts
// TableColumn 类型(简要)
interface TableColumn {
  key: string
  title: string
  width?: number | string
  align?: 'left' | 'center' | 'right'
  render?: (row: any, index: number) => any
}
  • 大数据量建议:
    • 使用分页控制每页数据量,避免一次性渲染过多行。
    • 对列宽进行合理约束,结合横向滚动避免内容拥挤。
    • 如需展示 500+ 行,建议采用虚拟列表技术(目前组件未内置,可自行集成)。