Skip to content

Table ​

数据表格。列定义驱动渲染,支持排序、斑马纹、边框、固定表头、加载中与空数据状态。

基础 ​

路径方法状态码耗时
GET /api/usersGET20012ms
POST /api/ordersPOST20145ms
GET /api/productsGET2008ms
PUT /api/users/1PUT500230ms
GET /api/not-foundGET4043ms
vue
<script setup lang="ts">
import { HTable } from 'happier-ui'
import type { HTableColumn } from 'happier-ui'

const columns: HTableColumn[] = [
  { key: 'name', title: '路径' },
  { key: 'method', title: '方法', width: 80, align: 'center' },
  { key: 'status', title: '状态码', width: 80, align: 'right' },
  { key: 'time', title: '耗时', width: 80, align: 'right' },
]

const data = [
  { id: '1', name: 'GET /api/users', status: 200, method: 'GET', time: '12ms' },
  { id: '2', name: 'POST /api/orders', status: 201, method: 'POST', time: '45ms' },
  { id: '3', name: 'GET /api/products', status: 200, method: 'GET', time: '8ms' },
]
</script>

<template>
  <h-table :columns="columns" :data="data" />
</template>

泛型行类型 ​

HTable 是泛型组件。传入具体行类型 T(普通 interface,无需索引签名),data 标注为 T[]、columns 标注为 HTableColumn<T>[] 后:column.key 会约束为 keyof T,#cell slot 的 row 推断为 T,无需任何 as 断言。

vue
<script setup lang="ts">
import { HTable } from 'happier-ui'
import type { HTableColumn } from 'happier-ui'

interface RequestLog {
  id: string
  name: string
  status: number
  method: string
  time: string
}

const columns: HTableColumn<RequestLog>[] = [
  { key: 'name', title: '路径', sortable: true },
  { key: 'status', title: '状态码', align: 'right', sortable: true },
]

const data: RequestLog[] = [
  { id: '1', name: 'GET /api/users', status: 200, method: 'GET', time: '12ms' },
]
</script>

<template>
  <h-table :columns="columns" :data="data">
    <!-- row 推断为 RequestLog;row.status 是 number,无需断言 -->
    <template #cell="{ column, row }">
      <span v-if="column.key === 'status'">{{ row.status >= 400 ? '错误' : '正常' }}</span>
      <template v-else>{{ row[column.key] }}</template>
    </template>
  </h-table>
</template>

不标注类型参数时(裸 HTableColumn[] / data 传 Record<string, unknown>[]),T 默认为 Record<string, unknown>,与旧用法完全兼容。

变体 ​

bordered + striped

路径方法状态码耗时
GET /api/usersGET20012ms
POST /api/ordersPOST20145ms
GET /api/productsGET2008ms
PUT /api/users/1PUT500230ms
GET /api/not-foundGET4043ms
vue
<h-table :columns="columns" :data="data" bordered striped />

排序 ​

当前排序:

路径方法状态码耗时
GET /api/usersGET20012ms
POST /api/ordersPOST20145ms
GET /api/productsGET2008ms
PUT /api/users/1PUT500230ms
GET /api/not-foundGET4043ms
vue
<script setup>
const sortState = ref(null)
</script>

<template>
  <h-table
    :columns="columns"
    :data="data"
    @sort="sortState = $event"
  />
</template>

加载中 ​

路径方法状态码耗时
GET /api/usersGET20012ms
POST /api/ordersPOST20145ms
GET /api/productsGET2008ms
PUT /api/users/1PUT500230ms
GET /api/not-foundGET4043ms
vue
<h-table :columns="columns" :data="data" loading />

空数据 ​

路径方法状态码耗时

暂无数据

vue
<h-table :columns="columns" :data="[]" />

自定义单元格 ​

路径方法状态码耗时
GET /api/usersGET20012ms
POST /api/ordersPOST20145ms
GET /api/productsGET2008ms
PUT /api/users/1PUT500230ms
GET /api/not-foundGET4043ms
vue
<h-table :columns="columns" :data="data" bordered striped>
  <template #cell="{ column, row }">
    <span v-if="column.key === 'status'" :style="{ color: statusColor(row.status) }">
      {{ row.status }}
    </span>
    <template v-else>{{ row[column.key] }}</template>
  </template>
</h-table>

API ​

Props ​

名称类型默认说明
columnsHTableColumn<T>[][]列定义(T 为行类型,默认 Record<string, unknown>)
dataT[][]数据行;标注具体 interface[] 即可获得类型推断
rowKeystring | ((row) => string)'id'行唯一标识
borderedbooleanfalse列间竖线边框
stripedbooleanfalse斑马纹
stickyHeaderbooleanfalse表头固定(需父容器限制高度并 overflow-y: auto)
emptyTextstring'暂无数据'空数据文案
loadingbooleanfalse加载中态

类型 ​

ts
// 泛型;默认 T = Record<string, unknown>(裸用法兼容)
interface HTableColumn<T extends object = Record<string, unknown>> {
  key: keyof T & string      // 约束到行字段名
  title: string
  width?: string | number    // 如 '120px' 或 120
  align?: 'left' | 'center' | 'right'
  sortable?: boolean
  render?: (row: T, index: number) => string | number
}

interface HTableSort {
  key: string
  order: 'asc' | 'desc'
}

Emits ​

事件载荷说明
sortHTableSort | null排序列变化时触发;null 表示取消排序

Slots ​

名称作用域说明
cell{ column, row, index }自定义单元格内容
empty—自定义空状态(默认显示 emptyText)
loading—自定义加载中状态

行为说明 ​

  • 排序为受控行为:组件仅维护 UI 排序指示图标,点击可排序列触发 sort emit,由父组件处理实际排序逻辑。
  • 排序状态切换:未排序 → 升序 → 降序 → 取消排序(按列头循环)。
  • 行 key 通过 rowKey prop 指定(字符串 key 名或函数);默认取 row.id。
  • render 函数返回 string/number,用于简单格式化;复杂渲染请使用 #cell slot。
  • loading 时若 data 有内容,显示 loading overlay 覆盖数据区;若 data 为空,显示 loading 指示。
  • 空数据时通过 #empty slot 自定义空状态,默认降级为 HEmpty。

无障碍 ​

  • 原生 <table> / <thead> / <tbody> / <th> / <td> 语义。
  • 排序按钮通过 role="columnheader" 隐式语义;排序图标 aria-hidden。
  • 加载中 spinner 使用 aria-label="加载中"。
  • 空状态通过 HEmpty 提供标题语义。

MIT License