表格

传入 columns 和 rows,表格连表头一起自己搭好。它被包在一个横向滚动容器里,所以列数超出手机可显示范围的表格会自己滚动,而不是把页面撑开。它以 table 和 dataTable 两个名字导出。

基础表格

页面大小渲染耗时
/4.1 kB12 毫秒
/docs12.7 kB31 毫秒
/examples9.4 kB24 毫秒
table({
  columns: [
    { key: 'page', header: '页面' },
    { key: 'size', header: '大小' },
    { key: 'time', header: '渲染耗时' },
  ],
  rows: [
    { page: '/', size: '4.1 kB', time: '12 毫秒' },
    { page: '/docs', size: '12.7 kB', time: '31 毫秒' },
    { page: '/examples', size: '9.4 kB', time: '24 毫秒' },
  ],
})

对齐

数字靠列尾对齐会更好读。

页面字节Gzip
/4,1121,204
/docs12,7043,910
/examples9,3882,744
table({
  columns: [
    { key: 'page', header: '页面' },
    { key: 'bytes', header: '字节', align: 'end' },
    { key: 'gzip', header: 'Gzip', align: 'end' },
  ],
  rows: [
    { page: '/', bytes: '4,112', gzip: '1,204' },
    { page: '/docs', bytes: '12,704', gzip: '3,910' },
    { page: '/examples', bytes: '9,388', gzip: '2,744' },
  ],
})

自定义单元格

带 render 函数的列会拿到整行数据,并返回单元格里该放的东西——标签片、链接,或者格式化好的数字。

页面大小状态
/docs/routing18.2 kB正常
/docs/data21.7 kB正常
/docs/islands24.1 kB失败
table({
  columns: [
    { header: '页面', render: (row) => link({ href: row.href }, row.page) },
    { key: 'size', header: '大小', align: 'end' },
    { header: '状态', align: 'end', render: (row) =>
      chip({ size: 'sm', dot: true, color: row.ok ? 'success' : 'danger' }, row.ok ? '正常' : '失败') },
  ],
  rows: [
    { page: '/docs/routing', href: '/zh/docs/routing', size: '18.2 kB', ok: true },
    { page: '/docs/data', href: '/zh/docs/data', size: '21.7 kB', ok: true },
    { page: '/docs/islands', href: '/zh/docs/islands', size: '24.1 kB', ok: false },
  ],
})

样式

striped 给行加上隔行底色,hover 高亮指针所在的行,dense 则收紧内边距,适合行数很多的表格。

斑马纹
名称数值
页面169
资源208
合计9.5 MB
悬停高亮 + 紧凑
名称数值
页面169
资源208
合计9.5 MB
stack({ gap: 'lg' },
  table({
    striped: true,
    caption: '斑马纹',
    columns: [{ key: 'name', header: '名称' }, { key: 'value', header: '数值', align: 'end' }],
    rows: [{ name: '页面', value: '169' }, { name: '资源', value: '208' }, { name: '合计', value: '9.5 MB' }],
  }),
  table({
    hover: true,
    dense: true,
    caption: '悬停高亮 + 紧凑',
    columns: [{ key: 'name', header: '名称' }, { key: 'value', header: '数值', align: 'end' }],
    rows: [{ name: '页面', value: '169' }, { name: '资源', value: '208' }, { name: '合计', value: '9.5 MB' }],
  }),
)

表格标题

标题会为那些绕过周围文字直接来到表格的人说明这是什么——只要表格不是紧跟在一个已经交代清楚的标题下面,就值得加上。

构建产出,最新在前
提交时间页面数
94a837a4 分钟前169
dcfaaae2 小时前161
table({
  caption: '构建产出,最新在前',
  columns: [
    { key: 'commit', header: '提交' },
    { key: 'when', header: '时间' },
    { key: 'pages', header: '页面数', align: 'end' },
  ],
  rows: [
    { commit: '94a837a', when: '4 分钟前', pages: '169' },
    { commit: 'dcfaaae', when: '2 小时前', pages: '161' },
  ],
})

由数据生成

行数据就是一个普通数组,所以通常直接就是 data() 已经加载好的东西,中间不需要任何适配层。

文章发布于阅读量
你好,世界2026-01-141,204
静态优先2026-02-02890
没有运行时2026-03-192,317
return (() => {
  const posts = [
    { title: '你好,世界', date: '2026-01-14', reads: 1204 },
    { title: '静态优先', date: '2026-02-02', reads: 890 },
    { title: '没有运行时', date: '2026-03-19', reads: 2317 },
  ]

  return table({
    hover: true,
    columns: [
      { key: 'title', header: '文章' },
      { key: 'date', header: '发布于' },
      { header: '阅读量', align: 'end', render: (post) => post.reads.toLocaleString('zh') },
    ],
    rows: posts,
  })
})()

自己写标记

省略 columns,表格就改为渲染它的子元素,于是带汇总行或分组表头的表格可以手写,同时照样享有样式和滚动容器。

属性

属性类型默认值说明
columnsTableColumn[]—每列一个 { key, header, align, render }。省略它就自己手写各行。
rowsobject[][]每行一个对象。
captionChild—表格上方的标题。
stripedbooleanfalse隔行加底色。
hoverbooleanfalse高亮指针所在的行。
densebooleanfalse更紧凑的单元格内边距。