Skip to content

Table 表格

用于展示多条结构类似的数据,并支持排序、选择、展开、分页等交互。

基础用法

最基本的表格用法,只需传入 data 数据和 columns 列配置即可。columns 是一个对象数组,每个对象描述一列,key 对应 data 中的字段名,title 为列头显示文字。

工号
姓名
部门
职位
城市
入职日期
状态
1001
张三
技术部
前端工程师
北京
2022-01-15
在职
1002
李四
产品部
产品经理
上海
2021-06-20
在职
1003
王五
设计部
UI设计师
广州
2023-03-10
在职
1004
赵六
市场部
市场专员
深圳
2024-01-05
实习
<template>
  <Table :data="tableData" :columns="columns" />
</template>

<script setup lang="ts">
import { ref } from 'vue'
import Table from '@/components/Table/Table.vue'

const columns = ref([
  { title: '工号', key: 'id', width: 80 },
  { title: '姓名', key: 'name', width: 100 },
  { title: '部门', key: 'dept', width: 120 },
  { title: '职位', key: 'role', width: 120 },
  { title: '城市', key: 'city', width: 100 },
  { title: '入职日期', key: 'date', width: 120 },
  { title: '状态', key: 'status', width: 80 }
])

const tableData = ref([
  { id: '1001', name: '张三', dept: '技术部', role: '前端工程师', city: '北京', date: '2022-01-15', status: '在职' },
  { id: '1002', name: '李四', dept: '产品部', role: '产品经理', city: '上海', date: '2021-06-20', status: '在职' },
  { id: '1003', name: '王五', dept: '设计部', role: 'UI设计师', city: '广州', date: '2023-03-10', status: '在职' },
  { id: '1004', name: '赵六', dept: '市场部', role: '市场专员', city: '深圳', date: '2024-01-05', status: '实习' }
])
</script>

带边框

通过 border 属性可以给表格添加纵向边框,使单元格边界更加清晰。适合数据列较多、需要在视觉上明确区分单元格时使用。

工号
姓名
部门
职位
城市
入职日期
状态
1001
张三
技术部
前端工程师
北京
2022-01-15
在职
1002
李四
产品部
产品经理
上海
2021-06-20
在职
1003
王五
设计部
UI设计师
广州
2023-03-10
在职
1004
赵六
市场部
市场专员
深圳
2024-01-05
实习
<template>
  <Table :data="tableData" :columns="columns" border />
</template>

<script setup lang="ts">
import { ref } from 'vue'
import Table from '@/components/Table/Table.vue'

const columns = ref([
  { title: '工号', key: 'id', width: 80 },
  { title: '姓名', key: 'name', width: 100 },
  { title: '部门', key: 'dept', width: 120 },
  { title: '职位', key: 'role', width: 120 },
  { title: '城市', key: 'city', width: 100 },
  { title: '入职日期', key: 'date', width: 120 },
  { title: '状态', key: 'status', width: 80 }
])

const tableData = ref([
  { id: '1001', name: '张三', dept: '技术部', role: '前端工程师', city: '北京', date: '2022-01-15', status: '在职' },
  { id: '1002', name: '李四', dept: '产品部', role: '产品经理', city: '上海', date: '2021-06-20', status: '在职' },
  { id: '1003', name: '王五', dept: '设计部', role: 'UI设计师', city: '广州', date: '2023-03-10', status: '在职' },
  { id: '1004', name: '赵六', dept: '市场部', role: '市场专员', city: '深圳', date: '2024-01-05', status: '实习' }
])
</script>

斑马纹

通过 stripe 属性可以呈现斑马纹效果,即奇偶行使用不同的背景色,能够有效引导视觉流,方便用户横向阅读数据。适合行数较多的表格。

工号
姓名
部门
职位
城市
入职日期
状态
1001
张三
技术部
前端工程师
北京
2022-01-15
在职
1002
李四
产品部
产品经理
上海
2021-06-20
在职
1003
王五
设计部
UI设计师
广州
2023-03-10
在职
1004
赵六
市场部
市场专员
深圳
2024-01-05
实习
1005
钱七
运营部
运营总监
杭州
2020-11-30
在职
<template>
  <Table :data="tableData" :columns="columns" stripe />
</template>

<script setup lang="ts">
import { ref } from 'vue'
import Table from '@/components/Table/Table.vue'

const columns = ref([
  { title: '工号', key: 'id', width: 80 },
  { title: '姓名', key: 'name', width: 100 },
  { title: '部门', key: 'dept', width: 120 },
  { title: '职位', key: 'role', width: 120 },
  { title: '城市', key: 'city', width: 100 },
  { title: '入职日期', key: 'date', width: 120 },
  { title: '状态', key: 'status', width: 80 }
])

const tableData = ref([
  { id: '1001', name: '张三', dept: '技术部', role: '前端工程师', city: '北京', date: '2022-01-15', status: '在职' },
  { id: '1002', name: '李四', dept: '产品部', role: '产品经理', city: '上海', date: '2021-06-20', status: '在职' },
  { id: '1003', name: '王五', dept: '设计部', role: 'UI设计师', city: '广州', date: '2023-03-10', status: '在职' },
  { id: '1004', name: '赵六', dept: '市场部', role: '市场专员', city: '深圳', date: '2024-01-05', status: '实习' },
  { id: '1005', name: '钱七', dept: '运营部', role: '运营总监', city: '杭州', date: '2020-11-30', status: '在职' }
])
</script>

排序

通过设置列的 sortable 属性可以开启该列的点击排序功能。排序规则为三轮循环:未排序 → 升序 → 降序 → 未排序。点击排序图标或列头均可触发排序。可以通过 defaultSort 属性设置初始排序状态,接受 prop(排序字段名)和 order(排序方向 'ascending''descending')两个参数。

工号
姓名
部门
职位
年龄
城市
入职日期
1005
钱七
运营部
运营总监
35
杭州
2020-11-30
1002
李四
产品部
产品经理
30
上海
2021-06-20
1003
王五
设计部
UI设计师
28
广州
2023-03-10
1001
张三
技术部
前端工程师
25
北京
2022-01-15
1004
赵六
市场部
市场专员
22
深圳
2024-01-05
<template>
  <Table
    :data="tableData"
    :columns="columns"
    border
    :defaultSort="{ prop: 'age', order: 'descending' }"
  />
</template>

<script setup lang="ts">
import { ref } from 'vue'
import Table from '@/components/Table/Table.vue'

const columns = ref([
  { title: '工号', key: 'id', width: 80 },
  { title: '姓名', key: 'name', width: 100, sortable: true },
  { title: '部门', key: 'dept', width: 120 },
  { title: '职位', key: 'role', width: 120 },
  { title: '年龄', key: 'age', width: 80, sortable: true, align: 'center' },
  { title: '城市', key: 'city', width: 100 },
  { title: '入职日期', key: 'date', width: 120 }
])

const tableData = ref([
  { id: '1001', name: '张三', dept: '技术部', role: '前端工程师', age: 25, city: '北京', date: '2022-01-15' },
  { id: '1002', name: '李四', dept: '产品部', role: '产品经理', age: 30, city: '上海', date: '2021-06-20' },
  { id: '1003', name: '王五', dept: '设计部', role: 'UI设计师', age: 28, city: '广州', date: '2023-03-10' },
  { id: '1004', name: '赵六', dept: '市场部', role: '市场专员', age: 22, city: '深圳', date: '2024-01-05' },
  { id: '1005', name: '钱七', dept: '运营部', role: '运营总监', age: 35, city: '杭州', date: '2020-11-30' }
])
</script>

行选择

通过设置列的 type: 'selection' 可以添加一列复选框,用于行选择。表头复选框为全选操作,选中某行后会高亮显示。行选择状态可在外部通过 selectedRows 等方式访问(后续版本将提供 selection-change 事件)。

工号
姓名
部门
职位
城市
入职日期
状态
1001
张三
技术部
前端工程师
北京
2022-01-15
在职
1002
李四
产品部
产品经理
上海
2021-06-20
在职
1003
王五
设计部
UI设计师
广州
2023-03-10
在职
1004
赵六
市场部
市场专员
深圳
2024-01-05
实习
<template>
  <Table :data="tableData" :columns="columns" border />
</template>

<script setup lang="ts">
import { ref } from 'vue'
import Table from '@/components/Table/Table.vue'

const columns = ref([
  { title: '选择', type: 'selection', width: 50 },
  { title: '工号', key: 'id', width: 80 },
  { title: '姓名', key: 'name', width: 100 },
  { title: '部门', key: 'dept', width: 120 },
  { title: '职位', key: 'role', width: 120 },
  { title: '城市', key: 'city', width: 100 },
  { title: '入职日期', key: 'date', width: 120 },
  { title: '状态', key: 'status', width: 80 }
])

const tableData = ref([
  { id: '1001', name: '张三', dept: '技术部', role: '前端工程师', city: '北京', date: '2022-01-15', status: '在职' },
  { id: '1002', name: '李四', dept: '产品部', role: '产品经理', city: '上海', date: '2021-06-20', status: '在职' },
  { id: '1003', name: '王五', dept: '设计部', role: 'UI设计师', city: '广州', date: '2023-03-10', status: '在职' },
  { id: '1004', name: '赵六', dept: '市场部', role: '市场专员', city: '深圳', date: '2024-01-05', status: '实习' }
])
</script>

索引列

通过设置列的 type: 'index' 可以显示一列行号。默认显示从 1 开始的序号,配合分页使用时,序号会根据当前页和每页条数自动计算。可以通过 title 属性自定义列头文字。

序号
工号
姓名
部门
职位
城市
入职日期
1
1001
张三
技术部
前端工程师
北京
2022-01-15
2
1002
李四
产品部
产品经理
上海
2021-06-20
3
1003
王五
设计部
UI设计师
广州
2023-03-10
4
1004
赵六
市场部
市场专员
深圳
2024-01-05
<template>
  <Table :data="tableData" :columns="columns" border />
</template>

<script setup lang="ts">
import { ref } from 'vue'
import Table from '@/components/Table/Table.vue'

const columns = ref([
  { title: '序号', type: 'index', width: 60 },
  { title: '工号', key: 'id', width: 80 },
  { title: '姓名', key: 'name', width: 100 },
  { title: '部门', key: 'dept', width: 120 },
  { title: '职位', key: 'role', width: 120 },
  { title: '城市', key: 'city', width: 100 },
  { title: '入职日期', key: 'date', width: 120 }
])

const tableData = ref([
  { id: '1001', name: '张三', dept: '技术部', role: '前端工程师', city: '北京', date: '2022-01-15' },
  { id: '1002', name: '李四', dept: '产品部', role: '产品经理', city: '上海', date: '2021-06-20' },
  { id: '1003', name: '王五', dept: '设计部', role: 'UI设计师', city: '广州', date: '2023-03-10' },
  { id: '1004', name: '赵六', dept: '市场部', role: '市场专员', city: '深圳', date: '2024-01-05' }
])
</script>

行展开

通过设置列的 type: 'expand' 可以添加一个展开列,点击后可以展开/收起该行的详细信息。展开的内容通过具名插槽渲染,插槽名称由 expandSlot 属性指定(默认为 'expand'),作用域参数 { row, rowIndex } 可访问当前行数据。expandKey 属性用于指定行数据的唯一标识字段,默认为 'id'

展开
工号
姓名
部门
职位
城市
状态
1001
张三
技术部
前端工程师
北京
在职
1002
李四
产品部
产品经理
上海
在职
1003
王五
设计部
UI设计师
广州
在职
1004
赵六
市场部
市场专员
深圳
实习
<template>
  <Table :data="tableData" :columns="columns" border>
    <template #expand="{ row }">
      <div class="expand-panel">
        <div class="expand-row">
          <span class="expand-item"><em>工号</em><span>{{ row.id }}</span></span>
          <span class="expand-item"><em>姓名</em><span>{{ row.name }}</span></span>
          <span class="expand-item"><em>部门</em><span>{{ row.dept }}</span></span>
          <span class="expand-item"><em>职位</em><span>{{ row.role }}</span></span>
        </div>
        <div class="expand-row">
          <span class="expand-item"><em>城市</em><span>{{ row.city }}</span></span>
          <span class="expand-item"><em>入职日期</em><span>{{ row.date }}</span></span>
          <span class="expand-item full"><em>备注</em><span>该员工入职以来表现良好,按时完成各项工作任务,积极参与团队协作,适合承担核心业务开发工作。</span></span>
        </div>
      </div>
    </template>
  </Table>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import Table from '@/components/Table/Table.vue'

const columns = ref([
  { title: '展开', type: 'expand', expandSlot: 'expand', width: 60 },
  { title: '工号', key: 'id', width: 80 },
  { title: '姓名', key: 'name', width: 100 },
  { title: '部门', key: 'dept', width: 120 },
  { title: '职位', key: 'role', width: 120 },
  { title: '城市', key: 'city', width: 100 },
  { title: '状态', key: 'status', width: 80 }
])

const tableData = ref([
  { id: '1001', name: '张三', dept: '技术部', role: '前端工程师', city: '北京', date: '2022-01-15', status: '在职' },
  { id: '1002', name: '李四', dept: '产品部', role: '产品经理', city: '上海', date: '2021-06-20', status: '在职' },
  { id: '1003', name: '王五', dept: '设计部', role: 'UI设计师', city: '广州', date: '2023-03-10', status: '在职' },
  { id: '1004', name: '赵六', dept: '市场部', role: '市场专员', city: '深圳', date: '2024-01-05', status: '实习' }
])
</script>

<style scoped>
.expand-panel {
  padding: 14px 16px;
  background: #f5f7fa;
}
.expand-row {
  display: flex;
  flex-wrap: wrap;
  margin-bottom: 10px;
}
.expand-row:last-child {
  margin-bottom: 0;
}
.expand-item {
  display: flex;
  align-items: baseline;
  min-width: 160px;
  margin-right: 32px;
}
.expand-item em {
  font-style: normal;
  color: #909399;
  font-size: 13px;
  width: 56px;
  flex-shrink: 0;
}
.expand-item span {
  color: #303133;
  font-size: 13px;
}
.expand-item.full {
  flex-basis: 100%;
  min-width: 0;
}
</style>

分页

通过 pagination 属性可以为表格添加分页功能。传入一个对象,包含 pageSize(每页条数)和 currentPage(当前页码)。表格会自动根据配置对数据进行分页,切页后排序状态会保留。如果不传入该属性,则不分页,显示全部数据。

工号
姓名
部门
职位
城市
入职日期
状态
1001
张三
技术部
前端工程师
北京
2022-01-15
在职
1002
李四
产品部
产品经理
上海
2021-06-20
在职
1003
王五
设计部
UI设计师
广州
2023-03-10
在职
1 / 3
<template>
  <Table
    :data="tableData"
    :columns="columns"
    border
    :pagination="{ pageSize: 3, currentPage: 1 }"
  />
</template>

<script setup lang="ts">
import { ref } from 'vue'
import Table from '@/components/Table/Table.vue'

const columns = ref([
  { title: '工号', key: 'id', width: 80 },
  { title: '姓名', key: 'name', width: 100 },
  { title: '部门', key: 'dept', width: 120 },
  { title: '职位', key: 'role', width: 120 },
  { title: '城市', key: 'city', width: 100 },
  { title: '入职日期', key: 'date', width: 120 },
  { title: '状态', key: 'status', width: 80 }
])

const tableData = ref([
  { id: '1001', name: '张三', dept: '技术部', role: '前端工程师', city: '北京', date: '2022-01-15', status: '在职' },
  { id: '1002', name: '李四', dept: '产品部', role: '产品经理', city: '上海', date: '2021-06-20', status: '在职' },
  { id: '1003', name: '王五', dept: '设计部', role: 'UI设计师', city: '广州', date: '2023-03-10', status: '在职' },
  { id: '1004', name: '赵六', dept: '市场部', role: '市场专员', city: '深圳', date: '2024-01-05', status: '实习' },
  { id: '1005', name: '钱七', dept: '运营部', role: '运营总监', city: '杭州', date: '2020-11-30', status: '在职' },
  { id: '1006', name: '孙八', dept: '财务部', role: '财务经理', city: '南京', date: '2022-08-15', status: '在职' },
  { id: '1007', name: '周九', dept: '人事部', role: '人事专员', city: '成都', date: '2023-05-20', status: '实习' }
])
</script>

加载状态

通过 loading 属性可以控制表格的加载状态。当设为 true 时,表格上方会覆盖一层半透明遮罩并显示旋转加载动画。常用于数据异步加载时给用户明确的等待反馈。设为 false 可关闭加载状态。

工号
姓名
部门
职位
城市
入职日期
状态
1001
张三
技术部
前端工程师
北京
2022-01-15
在职
1002
李四
产品部
产品经理
上海
2021-06-20
在职
1003
王五
设计部
UI设计师
广州
2023-03-10
在职
1004
赵六
市场部
市场专员
深圳
2024-01-05
实习
<template>
  <div class="demo-wrapper">
    <button class="trigger-btn" @click="loading = !loading">
      {{ loading ? '关闭加载' : '开启加载' }}
    </button>
    <Table
      :data="tableData"
      :columns="columns"
      border
      :loading="loading"
    />
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import Table from '@/components/Table/Table.vue'

const loading = ref(true)

const columns = ref([
  { title: '工号', key: 'id', width: 80 },
  { title: '姓名', key: 'name', width: 100 },
  { title: '部门', key: 'dept', width: 120 },
  { title: '职位', key: 'role', width: 120 },
  { title: '城市', key: 'city', width: 100 },
  { title: '入职日期', key: 'date', width: 120 },
  { title: '状态', key: 'status', width: 80 }
])

const tableData = ref([
  { id: '1001', name: '张三', dept: '技术部', role: '前端工程师', city: '北京', date: '2022-01-15', status: '在职' },
  { id: '1002', name: '李四', dept: '产品部', role: '产品经理', city: '上海', date: '2021-06-20', status: '在职' },
  { id: '1003', name: '王五', dept: '设计部', role: 'UI设计师', city: '广州', date: '2023-03-10', status: '在职' },
  { id: '1004', name: '赵六', dept: '市场部', role: '市场专员', city: '深圳', date: '2024-01-05', status: '实习' }
])
</script>

<style scoped>
.demo-wrapper {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.trigger-btn {
  align-self: flex-start;
  padding: 6px 14px;
  border: 1px solid #409eff;
  background: #fff;
  border-radius: 4px;
  color: #409eff;
  cursor: pointer;
  font-size: 13px;
}
.trigger-btn:hover {
  background: #ecf5ff;
}
</style>

固定列

通过设置列的 fixed 属性可以将列固定在左侧或右侧。固定列在横向滚动时始终保持可见,非常适合列数较多且有关键列(如姓名、操作列)需要始终展示的场景。fixed 可选值为 'left'(固定左侧)、'right'(固定右侧)或 true(等同于 'left')。建议同时为固定列设置明确的 width,否则可能无法正确固定。

工号
姓名
部门
职位
省份
城市
详细地址
邮编
联系电话
邮箱
入职日期
状态
操作
1001
张三
技术部
前端工程师
北京市
北京市
朝阳区建国路88号SOHO现代城A座1201室
100022
13800138001
zhangsan@example-company.com
2022-01-15
在职
1002
李四
产品部
产品经理
上海市
上海市
浦东新区世纪大道100号环球金融中心B座802室
200120
13800138002
lisi@example-company.com
2021-06-20
在职
1003
王五
设计部
UI设计师
广东省
广州市
天河区天河路123号太古汇写字楼18层
510620
13800138003
wangwu@example-company.com
2023-03-10
在职
1004
赵六
市场部
市场专员
浙江省
杭州市
西湖区文一路88号浙江大学科技园
310012
13800138004
zhaoliu@example-company.com
2024-01-05
实习
<template>
  <Table :data="tableData" :columns="columns" border>
    <template #action="{ row }">
      <button class="btn-action" @click="handleEdit(row)">编辑</button>
      <button class="btn-action btn-danger" @click="handleDelete(row)">删除</button>
    </template>
  </Table>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import Table from '@/components/Table/Table.vue'

const columns = ref([
  { title: '工号', key: 'id', width: 80, fixed: 'left' },
  { title: '姓名', key: 'name', width: 100, fixed: 'left' },
  { title: '部门', key: 'dept', width: 120 },
  { title: '职位', key: 'role', width: 120 },
  { title: '省份', key: 'province', width: 100 },
  { title: '城市', key: 'city', width: 100 },
  { title: '详细地址', key: 'address', width: 240 },
  { title: '邮编', key: 'zip', width: 100 },
  { title: '联系电话', key: 'phone', width: 130 },
  { title: '邮箱', key: 'email', width: 220 },
  { title: '入职日期', key: 'date', width: 120 },
  { title: '状态', key: 'status', width: 80 },
  { title: '操作', key: 'action', slot: 'action', width: 160, fixed: 'right', ellipsis: false }
])

const tableData = ref([
  { id: '1001', name: '张三', dept: '技术部', role: '前端工程师', province: '北京市', city: '北京市', address: '朝阳区建国路88号SOHO现代城A座1201室', zip: '100022', phone: '13800138001', email: 'zhangsan@example-company.com', date: '2022-01-15', status: '在职' },
  { id: '1002', name: '李四', dept: '产品部', role: '产品经理', province: '上海市', city: '上海市', address: '浦东新区世纪大道100号环球金融中心B座802室', zip: '200120', phone: '13800138002', email: 'lisi@example-company.com', date: '2021-06-20', status: '在职' },
  { id: '1003', name: '王五', dept: '设计部', role: 'UI设计师', province: '广东省', city: '广州市', address: '天河区天河路123号太古汇写字楼18层', zip: '510620', phone: '13800138003', email: 'wangwu@example-company.com', date: '2023-03-10', status: '在职' },
  { id: '1004', name: '赵六', dept: '市场部', role: '市场专员', province: '浙江省', city: '杭州市', address: '西湖区文一路88号浙江大学科技园', zip: '310012', phone: '13800138004', email: 'zhaoliu@example-company.com', date: '2024-01-05', status: '实习' }
])

const handleEdit = (row: any) => console.log('编辑', row)
const handleDelete = (row: any) => console.log('删除', row)
</script>

<style scoped>
button {
  padding: 4px 10px;
  margin-right: 4px;
  border: 1px solid #dcdfe6;
  background: #fff;
  border-radius: 4px;
  cursor: pointer;
  font-size: 12px;
  color: #606266;
}
button:last-child { margin-right: 0; }
button:hover {
  color: #409eff;
  border-color: #c6e2ff;
  background: #ecf5ff;
}
.btn-danger:hover {
  color: #f56c6c;
  border-color: #fbc4c4;
  background: #fef0f0;
}
</style>

多级表头

通过在列配置中使用 children 属性可以创建多级表头结构。含有 children 的列会作为父级表头,其下的子列会在下方渲染为多行表头。子列同样支持 sortablefixedwidth 等属性。多级表头常用于对列进行分组归类,提升大表格的可读性。

基本信息
职位信息
详细地址
入职日期
工号
姓名
部门
职位
城市
1001
张三
技术部
前端工程师
北京
北京市朝阳区建国路88号SOHO现代城
2022-01-15
1002
李四
产品部
产品经理
上海
上海市浦东新区世纪大道100号
2021-06-20
1003
王五
设计部
UI设计师
广州
广州市天河区天河路123号太古汇
2023-03-10
1004
赵六
市场部
市场专员
深圳
深圳市南山区科技路66号高新产业园
2024-01-05
<template>
  <Table :data="tableData" :columns="columns" border />
</template>

<script setup lang="ts">
import { ref } from 'vue'
import Table from '@/components/Table/Table.vue'

const columns = ref([
  {
    title: '基本信息',
    children: [
      { title: '工号', key: 'id', width: 80 },
      { title: '姓名', key: 'name', width: 100 }
    ]
  },
  {
    title: '职位信息',
    children: [
      { title: '部门', key: 'dept', width: 120 },
      { title: '职位', key: 'role', width: 120 },
      { title: '城市', key: 'city', width: 100 }
    ]
  },
  { title: '详细地址', key: 'address', width: 220 },
  { title: '入职日期', key: 'date', width: 120 }
])

const tableData = ref([
  { id: '1001', name: '张三', dept: '技术部', role: '前端工程师', city: '北京', address: '北京市朝阳区建国路88号SOHO现代城', date: '2022-01-15' },
  { id: '1002', name: '李四', dept: '产品部', role: '产品经理', city: '上海', address: '上海市浦东新区世纪大道100号', date: '2021-06-20' },
  { id: '1003', name: '王五', dept: '设计部', role: 'UI设计师', city: '广州', address: '广州市天河区天河路123号太古汇', date: '2023-03-10' },
  { id: '1004', name: '赵六', dept: '市场部', role: '市场专员', city: '深圳', address: '深圳市南山区科技路66号高新产业园', date: '2024-01-05' }
])
</script>

自定义列模板

通过设置列的 slot 属性指定插槽名称后,即可在 Table 组件上使用具名插槽自定义该列的渲染内容。插槽作用域提供 { row, column, rowIndex } 三个参数,分别对应当前行数据、列配置和行索引。这种方式适合在单元格中渲染按钮、标签、图标等复杂内容。操作列是典型的自定义列模板场景。

工号
姓名
部门
职位
城市
入职日期
状态
操作
1001
张三
技术部
前端工程师
北京
2022-01-15
在职
1002
李四
产品部
产品经理
上海
2021-06-20
在职
1003
王五
设计部
UI设计师
广州
2023-03-10
在职
1004
赵六
市场部
市场专员
深圳
2024-01-05
实习
<template>
  <Table :data="tableData" :columns="columns" border>
    <template #status="{ row }">
      <span :class="row.status === '在职' ? 'tag-success' : 'tag-warning'">
        {{ row.status }}
      </span>
    </template>
    <template #action="{ row }">
      <button class="btn-action" @click="handleEdit(row)">编辑</button>
      <button class="btn-action btn-danger" @click="handleDelete(row)">删除</button>
    </template>
  </Table>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import Table from '@/components/Table/Table.vue'

const columns = ref([
  { title: '工号', key: 'id', width: 80 },
  { title: '姓名', key: 'name', width: 100 },
  { title: '部门', key: 'dept', width: 120 },
  { title: '职位', key: 'role', width: 120 },
  { title: '城市', key: 'city', width: 100 },
  { title: '入职日期', key: 'date', width: 120 },
  { title: '状态', key: 'status', slot: 'status', width: 90, align: 'center' },
  { title: '操作', key: 'action', slot: 'action', width: 160, ellipsis: false }
])

const tableData = ref([
  { id: '1001', name: '张三', dept: '技术部', role: '前端工程师', city: '北京', date: '2022-01-15', status: '在职' },
  { id: '1002', name: '李四', dept: '产品部', role: '产品经理', city: '上海', date: '2021-06-20', status: '在职' },
  { id: '1003', name: '王五', dept: '设计部', role: 'UI设计师', city: '广州', date: '2023-03-10', status: '在职' },
  { id: '1004', name: '赵六', dept: '市场部', role: '市场专员', city: '深圳', date: '2024-01-05', status: '实习' }
])

const handleEdit = (row: any) => console.log('编辑', row)
const handleDelete = (row: any) => console.log('删除', row)
</script>

<style scoped>
.tag-success {
  display: inline-block;
  padding: 2px 8px;
  background: #f0f9eb;
  color: #67c23a;
  border-radius: 4px;
  font-size: 12px;
}
.tag-warning {
  display: inline-block;
  padding: 2px 8px;
  background: #fdf6ec;
  color: #e6a23c;
  border-radius: 4px;
  font-size: 12px;
}
button {
  padding: 4px 10px;
  margin-right: 4px;
  border: 1px solid #dcdfe6;
  background: #fff;
  border-radius: 4px;
  cursor: pointer;
  font-size: 12px;
  color: #606266;
}
button:last-child { margin-right: 0; }
button:hover {
  color: #409eff;
  border-color: #c6e2ff;
  background: #ecf5ff;
}
.btn-danger:hover {
  color: #f56c6c;
  border-color: #fbc4c4;
  background: #fef0f0;
}
</style>

单元格省略与 Tooltip

当单元格内容过长时,默认会进行文本省略(ellipsis 默认为 true)。同时会自动使用 Tooltip 在鼠标悬停时显示完整内容。可以通过设置 tooltip: false 关闭 Tooltip,或设置 tooltip: true 强制开启。tooltipConfig 属性可以统一配置 Tooltip 的行为,如 placement(位置)、showDelay(显示延迟毫秒数)。

工号
姓名
部门
职位
邮箱
公司地址
操作
1001
张三
技术部
前端工程师
zhangsan.developer@example-company.com
北京市朝阳区建国路88号SOHO现代城A座1201室
1002
李四
产品部
产品经理
lisi.product@example-company.com
上海市浦东新区世纪大道100号上海环球金融中心B座802室
1003
王五
设计部
UI设计师
wangwu.design@example-company.com
广州市天河区天河路123号太古汇写字楼18层
1004
赵六
市场部
市场专员
zhaoliu.marketing@example-company.com
深圳市南山区科技路66号高新产业园3号楼5层
<template>
  <Table :data="tableData" :columns="columns" border>
    <template #action="{ row }">
      <button @click="handleEdit(row)">编辑</button>
      <button @click="handleDelete(row)">删除</button>
    </template>
  </Table>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import Table from '@/components/Table/Table.vue'

const columns = ref([
  { title: '工号', key: 'id', width: 80 },
  { title: '姓名', key: 'name', width: 100 },
  { title: '部门', key: 'dept', width: 120 },
  { title: '职位', key: 'role', width: 120 },
  { title: '邮箱', key: 'email', width: 220 },
  { title: '公司地址', key: 'address', width: 260 },
  { title: '操作', key: 'action', slot: 'action', width: 160, ellipsis: false }
])

const tableData = ref([
  { id: '1001', name: '张三', dept: '技术部', role: '前端工程师', email: 'zhangsan.developer@example-company.com', address: '北京市朝阳区建国路88号SOHO现代城A座1201室' },
  { id: '1002', name: '李四', dept: '产品部', role: '产品经理', email: 'lisi.product@example-company.com', address: '上海市浦东新区世纪大道100号上海环球金融中心B座802室' },
  { id: '1003', name: '王五', dept: '设计部', role: 'UI设计师', email: 'wangwu.design@example-company.com', address: '广州市天河区天河路123号太古汇写字楼18层' },
  { id: '1004', name: '赵六', dept: '市场部', role: '市场专员', email: 'zhaoliu.marketing@example-company.com', address: '深圳市南山区科技路66号高新产业园3号楼5层' }
])

const handleEdit = (row: any) => console.log('编辑', row)
const handleDelete = (row: any) => console.log('删除', row)
</script>

<style scoped>
button {
  padding: 4px 10px;
  margin-right: 4px;
  border: 1px solid #dcdfe6;
  background: #fff;
  border-radius: 4px;
  cursor: pointer;
  font-size: 12px;
  color: #606266;
}
button:last-child { margin-right: 0; }
button:hover {
  color: #409eff;
  border-color: #c6e2ff;
  background: #ecf5ff;
}
</style>

复杂示例

综合运用排序、选择、索引、展开、固定列、分页、斑马纹等特性。该示例展示了 Table 组件在真实业务场景中的典型用法,包含了操作列的状态渲染、行操作按钮以及展开行的详细内容。

展开
序号
工号
姓名
部门
职位
城市
详细地址
入职日期
年龄
状态
操作
1
1005
钱七
运营部
运营总监
杭州
杭州市西湖区文一路88号浙江大学科技园
2020-11-30
35
休假中
2
1002
李四
产品部
产品经理
上海
上海市浦东新区世纪大道100号上海环球金融中心
2021-06-20
30
休假中
3
1003
王五
设计部
UI设计师
广州
广州市天河区天河路123号太古汇写字楼
2023-03-10
28
正常
1 / 2
<template>
  <Table
    :data="tableData"
    :columns="columns"
    border
    stripe
    :pagination="{ pageSize: 3, currentPage: 1 }"
    :defaultSort="{ prop: 'age', order: 'descending' }"
  >
    <template #status="{ row }">
      <span :class="`tag tag-${row.status}`">{{ statusMap[row.status] }}</span>
    </template>
    <template #action="{ row }">
      <button class="btn-action" @click="handleView(row)">查看</button>
      <button class="btn-action" @click="handleEdit(row)">编辑</button>
      <button class="btn-action btn-danger" @click="handleDelete(row)">删除</button>
    </template>
    <template #expand="{ row }">
      <div class="expand-box">
        <p><strong>详细地址:</strong>{{ row.address }}</p>
        <p><strong>入职时间:</strong>{{ row.date }}</p>
        <p><strong>员工备注:</strong>该员工入职以来表现良好,积极配合工作,按时完成任务,具备良好的团队协作精神。</p>
      </div>
    </template>
  </Table>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import Table from '@/components/Table/Table.vue'

const columns = ref([
  { title: '选择', type: 'selection', width: 50 },
  { title: '序号', type: 'index', width: 60 },
  { title: '展开', type: 'expand', expandSlot: 'expand', width: 60 },
  { title: '工号', key: 'id', width: 80, fixed: 'left' },
  { title: '姓名', key: 'name', width: 100, fixed: 'left', sortable: true },
  { title: '部门', key: 'dept', width: 120 },
  { title: '职位', key: 'role', width: 120 },
  { title: '城市', key: 'city', width: 100 },
  { title: '详细地址', key: 'address', width: 220, ellipsis: true },
  { title: '入职日期', key: 'date', width: 120 },
  { title: '年龄', key: 'age', width: 80, sortable: true, align: 'center' },
  { title: '状态', key: 'status', slot: 'status', width: 100, align: 'center' },
  { title: '操作', key: 'action', slot: 'action', width: 220, fixed: 'right', ellipsis: false }
])

const tableData = ref([
  { id: '1001', name: '张三', dept: '技术部', role: '前端工程师', city: '北京', address: '北京市朝阳区建国路88号SOHO现代城A座1201室', date: '2022-01-15', age: 25, status: 1 },
  { id: '1002', name: '李四', dept: '产品部', role: '产品经理', city: '上海', address: '上海市浦东新区世纪大道100号上海环球金融中心', date: '2021-06-20', age: 30, status: 2 },
  { id: '1003', name: '王五', dept: '设计部', role: 'UI设计师', city: '广州', address: '广州市天河区天河路123号太古汇写字楼', date: '2023-03-10', age: 28, status: 1 },
  { id: '1004', name: '赵六', dept: '市场部', role: '市场专员', city: '深圳', address: '深圳市南山区科技路66号高新产业园', date: '2024-01-05', age: 22, status: 3 },
  { id: '1005', name: '钱七', dept: '运营部', role: '运营总监', city: '杭州', address: '杭州市西湖区文一路88号浙江大学科技园', date: '2020-11-30', age: 35, status: 2 },
  { id: '1006', name: '孙八', dept: '财务部', role: '财务经理', city: '南京', address: '南京市鼓楼区中山北路100号鼓楼医院旁', date: '2022-08-15', age: 27, status: 1 }
])

const statusMap: Record<number, string> = { 1: '正常', 2: '休假中', 3: '离职' }

const handleView = (row: any) => console.log('查看', row)
const handleEdit = (row: any) => console.log('编辑', row)
const handleDelete = (row: any) => console.log('删除', row)
</script>

<style scoped>
.expand-box {
  padding: 12px 16px;
  background: #f5f7fa;
}
.expand-box p {
  margin: 0 0 6px;
  font-size: 13px;
  color: #606266;
}
.expand-box p:last-child { margin-bottom: 0; }
.tag {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 12px;
}
.tag-1 { background: #f0f9eb; color: #67c23a; }
.tag-2 { background: #fdf6ec; color: #e6a23c; }
.tag-3 { background: #fef0f0; color: #f56c6c; }
button {
  padding: 4px 10px;
  margin-right: 4px;
  border: 1px solid #dcdfe6;
  background: #fff;
  border-radius: 4px;
  cursor: pointer;
  font-size: 12px;
  color: #606266;
}
button:last-child { margin-right: 0; }
button:hover {
  color: #409eff;
  border-color: #c6e2ff;
  background: #ecf5ff;
}
.btn-danger:hover {
  color: #f56c6c;
  border-color: #fbc4c4;
  background: #fef0f0;
}
</style>

API

Table Attributes

NameDescriptionTypeDefault
data表格数据,为一个对象数组,每个对象代表一行数据array[]
columns列配置数组,每个对象描述一列的基本属性和行为array[]
border是否添加纵向边框booleanfalse
stripe是否显示斑马纹效果booleanfalse
loading是否显示加载状态遮罩booleanfalse
size表格尺寸,影响单元格内边距大小,可选值为 'large''default''small'stringdefault
height固定表头高度,传入数值时单位为 px,也可传入带单位的字符串number / string
maxHeight表格最大高度,超出后在表格容器内显示滚动条number / string
defaultSort初始排序状态,prop 为排序字段名,order'ascending''descending'object
pagination分页配置,对象包含 pageSize(每页条数)和 currentPage(当前页)object
expandKey展开行的唯一标识字段名,用于追踪展开状态stringid
rowClass自定义行类名,传入字符串或函数,函数参数为 (row, rowIndex)string / function
rowStyle自定义行样式,传入样式对象或函数,函数参数为 (row, rowIndex)object / function
cellClass自定义单元格类名,函数参数为 (row, column, rowIndex, colIndex)function
cellStyle自定义单元格样式,函数参数为 (row, column, rowIndex, colIndex)function
tooltipConfig单元格 Tooltip 配置,可配置 placement(位置)、showDelayhideDelayobject

TableColumn Attributes

NameDescriptionTypeDefault
title列头显示的文字string
key对应 data 中的字段名,用于取单元格值string
width列宽度,单位为 px,建议为固定列和关键列设置明确宽度number
align单元格文本对齐方式,可选 'left'(居左)、'center'(居中)、'right'(居右)stringleft
slot插槽名称,定义后可在 Table 上使用具名插槽自定义该列渲染内容string
sortable是否启用该列的点击排序功能booleanfalse
fixed固定列位置,可选 'left'(固定左侧)、'right'(固定右侧)或 true(固定左侧)string / booleanfalse
type列类型,可选 'selection'(复选框)、'index'(行号)、'expand'(展开列)string
expandSlot展开行的插槽名称,与 type: 'expand' 配合使用stringexpand
ellipsis单元格文本过长时是否省略并用 Tooltip 显示完整内容,默认为 truebooleantrue
tooltip是否强制启用 Tooltip 显示溢出内容,覆盖 ellipsis 的默认行为boolean
className自定义该列所有单元格的类名string
style自定义该列所有单元格的样式对象object
children子列配置数组,用于构建多级表头,含此属性的列作为父级表头array

Table Events

NameDescriptionType
Table 组件当前版本暂未暴露事件,后续版本将补充 selection-change 等事件

Table Slots

NameDescriptionScope
(自定义列插槽)通过 columns 中各列的 slot 属性指定插槽名称后,在此定义对应插槽的内容{ row, column, rowIndex }
expand行展开后的详细内容插槽,与 type: 'expand' 列配合使用{ row, rowIndex }

Column Type 可选值

ValueDescription
selection复选框列,用于多行选择,表头复选框为全选功能
index索引列,显示从 1 开始的行号,配合分页时自动计算偏移
expand展开列,点击可展开/收起该行,显示详细信息

Column Fixed 可选值

ValueDescription
left固定在左侧,横向滚动时始终可见
right固定在右侧,横向滚动时始终可见
true等同于 'left',固定在左侧
false不固定,随表格横向滚动(默认值)

Column Align 可选值

ValueDescription
left文本居左对齐,单元格内容靠左显示
center文本居中对齐,单元格内容居中显示
right文本居右对齐,单元格内容靠右显示

Table Size 可选值

ValueDescription
large大尺寸,单元格内边距较大,适合数据密度低的场景
default默认尺寸,中等边距,适合大多数场景
small小尺寸,单元格内边距紧凑,适合数据密度高的场景