Nuxt UI v3-alpha 已发布!

尝试一下
组件

表格

在表格中显示数据。

用法

使用 rows 道具设置要在表格中显示的数据。默认情况下,表格将显示行中的所有字段。

ID姓名标题电子邮件角色
1Lindsay Walton前端开发人员[email protected]成员
2Courtney Henry设计师[email protected]管理员
3Tom Cook产品总监[email protected]成员
4Whitney Francis文案[email protected]管理员
5Leonard Krasner高级设计师[email protected]所有者
6Floyd Miles首席设计师[email protected]成员
<script setup lang="ts">
const people = [{
  id: 1,
  name: 'Lindsay Walton',
  title: 'Front-end Developer',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 2,
  name: 'Courtney Henry',
  title: 'Designer',
  email: '[email protected]',
  role: 'Admin'
}, {
  id: 3,
  name: 'Tom Cook',
  title: 'Director of Product',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 4,
  name: 'Whitney Francis',
  title: 'Copywriter',
  email: '[email protected]',
  role: 'Admin'
}, {
  id: 5,
  name: 'Leonard Krasner',
  title: 'Senior Designer',
  email: '[email protected]',
  role: 'Owner'
}, {
  id: 6,
  name: 'Floyd Miles',
  title: 'Principal Designer',
  email: '[email protected]',
  role: 'Member'
}]
</script>

<template>
  <UTable :rows="people" />
</template>

使用 columns 道具来配置要显示的列。它是一个包含以下属性的对象数组。

  • label - 在表格标题中显示的标签。可以通过 column-attribute 道具进行更改。
  • key - 要从行数据中显示的字段。
  • sortable - 该列是否可排序。默认为 false
  • direction - 首次单击时要使用的排序方向。默认为 asc
  • class - 要应用于列单元格的类。
  • rowClass - 要应用于数据列单元格的类。
  • sort - 传递您自己的 sort 函数。默认为简单的大于 / 小于比较。

sort 函数的参数为:值 A,值 B,方向 - 'asc' 或 'desc'

示例 sort 函数

(a, b, direction) => {
  if (!a || !b) return 0
  const aPrice = parseInt(a.replace(/[,$]/g, ""))
  const bPrice = parseInt(b.replace(/[,$]/g, ""))
  return direction === "asc" ? aPrice - bPrice : bPrice - aPrice
}
ID用户名职位电子邮件
1Lindsay Walton前端开发人员[email protected]成员
2Courtney Henry设计师[email protected]管理员
3Tom Cook产品总监[email protected]成员
4Whitney Francis文案[email protected]管理员
5Leonard Krasner高级设计师[email protected]所有者
6Floyd Miles首席设计师[email protected]成员
<script setup lang="ts">
const columns = [{
  key: 'id',
  label: 'ID'
}, {
  key: 'name',
  label: 'User name'
}, {
  key: 'title',
  label: 'Job position'
}, {
  key: 'email',
  label: 'Email'
}, {
  key: 'role'
}]

const people = [{
  id: 1,
  name: 'Lindsay Walton',
  title: 'Front-end Developer',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 2,
  name: 'Courtney Henry',
  title: 'Designer',
  email: '[email protected]',
  role: 'Admin'
}, {
  id: 3,
  name: 'Tom Cook',
  title: 'Director of Product',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 4,
  name: 'Whitney Francis',
  title: 'Copywriter',
  email: '[email protected]',
  role: 'Admin'
}, {
  id: 5,
  name: 'Leonard Krasner',
  title: 'Senior Designer',
  email: '[email protected]',
  role: 'Owner'
}, {
  id: 6,
  name: 'Floyd Miles',
  title: 'Principal Designer',
  email: '[email protected]',
  role: 'Member'
}]
</script>

<template>
  <UTable :columns="columns" :rows="people" />
</template>

您可以轻松地使用 SelectMenu 组件来更改要显示的列。

ID姓名标题电子邮件角色
1Lindsay Walton前端开发人员[email protected]成员
2Courtney Henry设计师[email protected]管理员
3Tom Cook产品总监[email protected]成员
4Whitney Francis文案[email protected]管理员
5Leonard Krasner高级设计师[email protected]所有者
6Floyd Miles首席设计师[email protected]成员
<script setup lang="ts">
const columns = [{
  key: 'id',
  label: 'ID'
}, {
  key: 'name',
  label: 'Name'
}, {
  key: 'title',
  label: 'Title'
}, {
  key: 'email',
  label: 'Email'
}, {
  key: 'role',
  label: 'Role'
}]

const selectedColumns = ref([...columns])

const people = [{
  id: 1,
  name: 'Lindsay Walton',
  title: 'Front-end Developer',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 2,
  name: 'Courtney Henry',
  title: 'Designer',
  email: '[email protected]',
  role: 'Admin'
}, {
  id: 3,
  name: 'Tom Cook',
  title: 'Director of Product',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 4,
  name: 'Whitney Francis',
  title: 'Copywriter',
  email: '[email protected]',
  role: 'Admin'
}, {
  id: 5,
  name: 'Leonard Krasner',
  title: 'Senior Designer',
  email: '[email protected]',
  role: 'Owner'
}, {
  id: 6,
  name: 'Floyd Miles',
  title: 'Principal Designer',
  email: '[email protected]',
  role: 'Member'
}]
</script>

<template>
  <div>
    <div class="flex px-3 py-3.5 border-b border-gray-200 dark:border-gray-700">
      <USelectMenu v-model="selectedColumns" :options="columns" multiple placeholder="Columns" />
    </div>

    <UTable :columns="selectedColumns" :rows="people" />
  </div>
</template>

您可以通过将 class 传递给行来对 trtd 元素应用样式。

此外,您可以通过将 class 传递给列来对 th 元素应用样式。

#数量姓名
1100苹果
20橙子
330香蕉
45芒果
<script setup lang="ts">
const columns = [{
  key: 'id',
  label: '#'
}, {
  key: 'quantity',
  label: 'Quantity',
  class: 'italic'
}, {
  key: 'name',
  label: 'Name'
}]

const items = [{
  id: 1,
  name: 'Apple',
  quantity: { value: 100, class: 'bg-green-500/50 dark:bg-green-400/50' }
}, {
  id: 2,
  name: 'Orange',
  quantity: { value: 0 },
  class: 'bg-red-500/50 dark:bg-red-400/50 animate-pulse'
}, {
  id: 3,
  name: 'Banana',
  quantity: { value: 30, class: 'bg-green-500/50 dark:bg-green-400/50' }
}, {
  id: 4,
  name: 'Mango',
  quantity: { value: 5, class: 'bg-green-500/50 dark:bg-green-400/50' }
}]
</script>

<template>
  <UTable :rows="items" :columns="columns">
    <template #quantity-data="{ row }">
      {{ row.quantity.value }}
    </template>
  </UTable>
</template>

可排序

通过在列配置中将 sortable 属性设置为 true,您可以使列可排序。

您可以通过 direction 属性指定每列的默认方向。它可以是 ascdesc,但默认为 asc

ID角色
1Lindsay Walton前端开发人员[email protected]成员
2Courtney Henry设计师[email protected]管理员
3Tom Cook产品总监[email protected]成员
4Whitney Francis文案[email protected]管理员
5Leonard Krasner高级设计师[email protected]所有者
6Floyd Miles首席设计师[email protected]成员
<script setup lang="ts">
const columns = [{
  key: 'id',
  label: 'ID'
}, {
  key: 'name',
  label: 'Name',
  sortable: true
}, {
  key: 'title',
  label: 'Title',
  sortable: true
}, {
  key: 'email',
  label: 'Email',
  sortable: true,
  direction: 'desc' as const
}, {
  key: 'role',
  label: 'Role'
}]

const people = [{
  id: 1,
  name: 'Lindsay Walton',
  title: 'Front-end Developer',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 2,
  name: 'Courtney Henry',
  title: 'Designer',
  email: '[email protected]',
  role: 'Admin'
}, {
  id: 3,
  name: 'Tom Cook',
  title: 'Director of Product',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 4,
  name: 'Whitney Francis',
  title: 'Copywriter',
  email: '[email protected]',
  role: 'Admin'
}, {
  id: 5,
  name: 'Leonard Krasner',
  title: 'Senior Designer',
  email: '[email protected]',
  role: 'Owner'
}, {
  id: 6,
  name: 'Floyd Miles',
  title: 'Principal Designer',
  email: '[email protected]',
  role: 'Member'
}]
</script>

<template>
  <UTable :columns="columns" :rows="people" />
</template>

默认排序

您可以通过 sort 道具指定表格的默认排序。它是一个包含以下属性的对象。

  • column - 要排序的列。
  • direction - 排序方向。可以是 ascdesc,默认为 asc

这将设置默认排序,即使没有将任何列设置为 sortable,它也会起作用。

<script setup lang="ts">
const sort = ref({
  column: 'name',
  direction: 'desc'
})

const columns = [{
  label: 'Name',
  key: 'name',
  sortable: true
}]

const people = [{
  id: 1,
  name: 'Lindsay Walton',
  title: 'Front-end Developer',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 2,
  name: 'Courtney Henry',
  title: 'Designer',
  email: '[email protected]',
  role: 'Admin'
}]
</script>

<template>
  <UTable :sort="sort" :columns="columns" :rows="people" />
</template>

响应式排序

您可以使用 v-model:sort 使排序响应式。您也可以使用 @update:sort 来调用您自己的函数,并使用排序数据。

从 API 提取数据时,我们可以利用 useFetchuseAsyncData 可组合函数,根据排序列和方向提取数据,每当 sort 响应式元素更改时。

这样做时,您可能需要将 sort-mode 道具设置为 manual 以禁用自动排序并按原样返回行。

<script setup lang="ts">
// Ensure it uses `ref` instead of `reactive`.
const sort = ref({
  column: 'name',
  direction: 'desc'
})

const columns = [{
  label: 'Name',
  key: 'name',
  sortable: true
}]

const { data, status } = await useLazyFetch(() => `/api/users?orderBy=${sort.value.column}&order=${sort.value.direction}`)
</script>

<template>
  <UTable v-model:sort="sort" :loading="status === 'pending'" :columns="columns" :rows="data" sort-mode="manual" />
</template>
我们在这里将函数传递给 useLazyFetch 以使 URL 响应式,但您可以使用 query / params 选项以及 watch

自定义排序

使用 sort-button 道具来自定义标题中的排序按钮。您可以通过此道具传递 Button 组件的所有道具来进行自定义,或者通过 ui.table.default.sortButton 全局进行自定义。它的图标默认为 i-heroicons-arrows-up-down-20-solid

ID角色
1Lindsay Walton前端开发人员[email protected]成员
2Courtney Henry设计师[email protected]管理员
3Tom Cook产品总监[email protected]成员
4Whitney Francis文案[email protected]管理员
5Leonard Krasner高级设计师[email protected]所有者
6Floyd Miles首席设计师[email protected]成员
<template>
  <UTable
    sort-asc-icon="i-heroicons-arrow-up-20-solid"
    sort-desc-icon="i-heroicons-arrow-down-20-solid"
    :sort-button="{ icon: 'i-heroicons-sparkles-20-solid', color: 'primary', variant: 'outline', size: '2xs', square: false, ui: { rounded: 'rounded-full' } }"
    class="w-full"
    :columns="[{ key: 'id', label: 'ID' }, { key: 'name', label: 'Name', sortable: true }, { key: 'title', label: 'Title', sortable: true }, { key: 'email', label: 'Email', sortable: true }, { key: 'role', label: 'Role' }]"
    :rows="[{ id: 1, name: 'Lindsay Walton', title: 'Front-end Developer', email: '[email protected]', role: 'Member' }, { id: 2, name: 'Courtney Henry', title: 'Designer', email: '[email protected]', role: 'Admin' }, { id: 3, name: 'Tom Cook', title: 'Director of Product', email: '[email protected]', role: 'Member' }, { id: 4, name: 'Whitney Francis', title: 'Copywriter', email: '[email protected]', role: 'Admin' }, { id: 5, name: 'Leonard Krasner', title: 'Senior Designer', email: '[email protected]', role: 'Owner' }, { id: 6, name: 'Floyd Miles', title: 'Principal Designer', email: '[email protected]', role: 'Member' }]"
  />
</template>

使用 sort-asc-icon 道具设置不同的图标,或在 ui.table.default.sortAscIcon 中全局更改它。默认为 i-heroicons-bars-arrow-up-20-solid

使用 sort-desc-icon 道具设置不同的图标,或在 ui.table.default.sortDescIcon 中全局更改它。默认为 i-heroicons-bars-arrow-down-20-solid

您还可以自定义整个标题单元格,有关更多信息,请阅读 插槽 部分。

可选择

使用 v-model 使表格可选择。 v-model 将是一个包含已选择行的数组。

ID姓名标题电子邮件角色
1Lindsay Walton前端开发人员[email protected]成员
2Courtney Henry设计师[email protected]管理员
3Tom Cook产品总监[email protected]成员
4Whitney Francis文案[email protected]管理员
5Leonard Krasner高级设计师[email protected]所有者
6Floyd Miles首席设计师[email protected]成员
<script setup lang="ts">
const people = [{
  id: 1,
  name: 'Lindsay Walton',
  title: 'Front-end Developer',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 2,
  name: 'Courtney Henry',
  title: 'Designer',
  email: '[email protected]',
  role: 'Admin'
}, {
  id: 3,
  name: 'Tom Cook',
  title: 'Director of Product',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 4,
  name: 'Whitney Francis',
  title: 'Copywriter',
  email: '[email protected]',
  role: 'Admin'
}, {
  id: 5,
  name: 'Leonard Krasner',
  title: 'Senior Designer',
  email: '[email protected]',
  role: 'Owner'
}, {
  id: 6,
  name: 'Floyd Miles',
  title: 'Principal Designer',
  email: '[email protected]',
  role: 'Member'
}]

const selected = ref([people[1]])
</script>

<template>
  <UTable v-model="selected" :rows="people" />
</template>
您可以使用 by 道具根据字段比较对象,而不是比较对象实例。我们复制了 Headless UI Combobox 的行为。

您也可以在 Table 上添加 select 监听器,使行可点击。该函数将以行作为第一个参数接收。

您可以使用它来导航到页面,打开模态框,甚至手动选择行。

ID姓名标题电子邮件角色
1Lindsay Walton前端开发人员[email protected]成员
2Courtney Henry设计师[email protected]管理员
3Tom Cook产品总监[email protected]成员
4Whitney Francis文案[email protected]管理员
5Leonard Krasner高级设计师[email protected]所有者
<script setup lang="ts">
const people = [{
  id: 1,
  name: 'Lindsay Walton',
  title: 'Front-end Developer',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 2,
  name: 'Courtney Henry',
  title: 'Designer',
  email: '[email protected]',
  role: 'Admin'
}, {
  id: 3,
  name: 'Tom Cook',
  title: 'Director of Product',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 4,
  name: 'Whitney Francis',
  title: 'Copywriter',
  email: '[email protected]',
  role: 'Admin'
}, {
  id: 5,
  name: 'Leonard Krasner',
  title: 'Senior Designer',
  email: '[email protected]',
  role: 'Owner'
}]

function select(row) {
  const index = selected.value.findIndex(item => item.id === row.id)
  if (index === -1) {
    selected.value.push(row)
  } else {
    selected.value.splice(index, 1)
  }
}

const selected = ref([people[1]])
</script>

<template>
  <UTable v-model="selected" :rows="people" @select="select" />
</template>

可搜索

您可以轻松地使用 Input 组件来过滤行。

ID姓名标题电子邮件角色
1Lindsay Walton前端开发人员[email protected]成员
2Courtney Henry设计师[email protected]管理员
3Tom Cook产品总监[email protected]成员
4Whitney Francis文案[email protected]管理员
5Leonard Krasner高级设计师[email protected]所有者
6Floyd Miles首席设计师[email protected]成员
<script setup lang="ts">
const columns = [{
  key: 'id',
  label: 'ID'
}, {
  key: 'name',
  label: 'Name'
}, {
  key: 'title',
  label: 'Title'
}, {
  key: 'email',
  label: 'Email'
}, {
  key: 'role',
  label: 'Role'
}]

const people = [{
  id: 1,
  name: 'Lindsay Walton',
  title: 'Front-end Developer',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 2,
  name: 'Courtney Henry',
  title: 'Designer',
  email: '[email protected]',
  role: 'Admin'
}, {
  id: 3,
  name: 'Tom Cook',
  title: 'Director of Product',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 4,
  name: 'Whitney Francis',
  title: 'Copywriter',
  email: '[email protected]',
  role: 'Admin'
}, {
  id: 5,
  name: 'Leonard Krasner',
  title: 'Senior Designer',
  email: '[email protected]',
  role: 'Owner'
}, {
  id: 6,
  name: 'Floyd Miles',
  title: 'Principal Designer',
  email: '[email protected]',
  role: 'Member'
}]

const q = ref('')

const filteredRows = computed(() => {
  if (!q.value) {
    return people
  }

  return people.filter((person) => {
    return Object.values(person).some((value) => {
      return String(value).toLowerCase().includes(q.value.toLowerCase())
    })
  })
})
</script>

<template>
  <div>
    <div class="flex px-3 py-3.5 border-b border-gray-200 dark:border-gray-700">
      <UInput v-model="q" placeholder="Filter people..." />
    </div>

    <UTable :rows="filteredRows" :columns="columns" />
  </div>
</template>

可分页

您可以轻松地使用 Pagination 组件来对行进行分页。

ID姓名标题电子邮件角色
1Lindsay Walton前端开发人员[email protected]成员
2Courtney Henry设计师[email protected]管理员
3Tom Cook产品总监[email protected]成员
4Whitney Francis文案[email protected]管理员
5Leonard Krasner高级设计师[email protected]所有者
<script setup lang="ts">
const people = [{
  id: 1,
  name: 'Lindsay Walton',
  title: 'Front-end Developer',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 2,
  name: 'Courtney Henry',
  title: 'Designer',
  email: '[email protected]',
  role: 'Admin'
}, {
  id: 3,
  name: 'Tom Cook',
  title: 'Director of Product',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 4,
  name: 'Whitney Francis',
  title: 'Copywriter',
  email: '[email protected]',
  role: 'Admin'
}, {
  id: 5,
  name: 'Leonard Krasner',
  title: 'Senior Designer',
  email: '[email protected]',
  role: 'Owner'
}, {
  id: 6,
  name: 'Floyd Miles',
  title: 'Principal Designer',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 7,
  name: 'Emily Selman',
  title: 'VP, User Experience',
  email: '',
  role: 'Admin'
}, {
  id: 8,
  name: 'Kristin Watson',
  title: 'VP, Human Resources',
  email: '',
  role: 'Member'
}, {
  id: 9,
  name: 'Emma Watson',
  title: 'Front-end Developer',
  email: '',
  role: 'Member'
}, {
  id: 10,
  name: 'John Doe',
  title: 'Designer',
  email: '',
  role: 'Admin'
}, {
  id: 11,
  name: 'Jane Doe',
  title: 'Director of Product',
  email: '',
  role: 'Member'
}, {
  id: 12,
  name: 'John Smith',
  title: 'Copywriter',
  email: '',
  role: 'Admin'
}, {
  id: 13,
  name: 'Jane Smith',
  title: 'Senior Designer',
  email: '',
  role: 'Owner'
}]

const page = ref(1)
const pageCount = 5

const rows = computed(() => {
  return people.slice((page.value - 1) * pageCount, (page.value) * pageCount)
})
</script>

<template>
  <div>
    <UTable :rows="rows" />

    <div class="flex justify-end px-3 py-3.5 border-t border-gray-200 dark:border-gray-700">
      <UPagination v-model="page" :page-count="pageCount" :total="people.length" />
    </div>
  </div>
</template>

可扩展

您可以使用 v-model:expand 在表格组件中启用行扩展功能。它维护一个包含 openedRows 数组和 row 对象的对象,用于跟踪当前扩展行的索引。

使用扩展插槽时,您可以在插槽作用域中访问 row 属性,该属性包含触发扩展/折叠操作的行的相关数据。这使您可以根据行的相关数据来自定义扩展内容。

展开ID姓名标题电子邮件角色
1Lindsay Walton前端开发人员[email protected]成员
{
  "id": 1,
  "name": "Lindsay Walton",
  "title": "Front-end Developer",
  "email": "[email protected]",
  "role": "Member"
}
2Courtney Henry设计师[email protected]管理员
3Tom Cook产品总监[email protected]成员
4Whitney Francis文案[email protected]管理员
5Leonard Krasner高级设计师[email protected]所有者
6Floyd Miles首席设计师[email protected]成员
<script setup lang='ts'>
const people = [{
  id: 1,
  name: 'Lindsay Walton',
  title: 'Front-end Developer',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 2,
  name: 'Courtney Henry',
  title: 'Designer',
  email: '[email protected]',
  role: 'Admin'
}, {
  id: 3,
  name: 'Tom Cook',
  title: 'Director of Product',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 4,
  name: 'Whitney Francis',
  title: 'Copywriter',
  email: '[email protected]',
  role: 'Admin'
}, {
  id: 5,
  name: 'Leonard Krasner',
  title: 'Senior Designer',
  email: '[email protected]',
  role: 'Owner'
}, {
  id: 6,
  name: 'Floyd Miles',
  title: 'Principal Designer',
  email: '[email protected]',
  role: 'Member'
}]

const expand = ref({
  openedRows: [people[0]],
  row: {}
})
</script>

<template>
  <UTable v-model:expand="expand" :rows="people">
    <template #expand="{ row }">
      <div class="p-4">
        <pre>{{ row }}</pre>
      </div>
    </template>
  </UTable>
</template>

事件扩展

@update:expand 事件在扩展行时发出。此事件提供了扩展行的当前状态以及触发事件的行的相关数据。

要使用 @update:expand 事件,请将其添加到您的 UTable 组件中。事件处理程序将接收一个包含以下属性的对象。

  • openedRows: 当前扩展行的索引数组。
  • row: 触发扩展/折叠操作的行数据。
<script setup lang="ts">
const { data, pending } = await useLazyFetch(() => `/api/users`)

const handleExpand = ({ openedRows, row }) => {
  console.log('opened Rows:', openedRows);
  console.log('Row Data:', row);
};

const expand = ref({
  openedRows: [],
  row: null
})

</script>
<template>
  <UTable v-model="expand" :loading="pending" :rows="data" @update:expand="handleExpand">
    <template #expand="{ row }">
        <div class="p-4">
          <pre>{{ row }}</pre>
        </div>
      </template>
  </UTable>
</template>

多行扩展

控制表格中是否可以同时扩展多行。

<template>
  <!-- Allow only one row to be expanded at a time -->
  <UTable :multiple-expand="false" />

  <!-- Default behavior: Allow multiple rows to be expanded simultaneously -->
  <UTable :multiple-expand="true" />

  <!-- Or simply -->
  <UTable />
</template>

禁用行扩展

您可以通过在行数据中添加 disabledExpand 属性来禁用 UTable 组件中特定行的扩展功能。

重要提示:使用 disabledExpand 时,您必须为 UTable 组件定义 columns 道具。否则,表格将呈现所有属性作为列,包括 disabledExpand 属性。

展开姓名标题电子邮件角色
Lindsay Walton前端开发人员[email protected]成员
Courtney Henry设计师[email protected]管理员
Tom Cook产品总监[email protected]成员
Whitney Francis文案[email protected]管理员
Leonard Krasner高级设计师[email protected]所有者
Floyd Miles首席设计师[email protected]成员
<script setup>
const people = [{
  id: 1,
  name: 'Lindsay Walton',
  title: 'Front-end Developer',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 2,
  name: 'Courtney Henry',
  title: 'Designer',
  email: '[email protected]',
  role: 'Admin',
  disabledExpand: true
}, {
  id: 3,
  name: 'Tom Cook',
  title: 'Director of Product',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 4,
  name: 'Whitney Francis',
  title: 'Copywriter',
  email: '[email protected]',
  role: 'Admin',
  disabledExpand: true
}, {
  id: 5,
  name: 'Leonard Krasner',
  title: 'Senior Designer',
  email: '[email protected]',
  role: 'Owner'
}, {
  id: 6,
  name: 'Floyd Miles',
  title: 'Principal Designer',
  email: '[email protected]',
  role: 'Member',
  disabledExpand: true
}]
const columns = [
  {
    label: 'Name',
    key: 'name'
  },
  {
    label: 'title',
    key: 'title'
  },
  {
    label: 'Email',
    key: 'email'
  },
  {
    label: 'role',
    key: 'role'
  }
]

const expand = ref({
  openedRows: [],
  row: null
})
</script>

<template>
  <UTable v-model:expand="expand" :rows="people" :columns="columns">
    <template #expand="{ row }">
      <div class="p-4">
        <pre>{{ row }}</pre>
      </div>
    </template>
  </UTable>
</template>

加载中

使用 loading 道具来指示数据当前正在加载,并使用不确定的 Progress 条。

您可以使用 progress 道具来自定义进度条的 coloranimation,或者在 ui.table.default.progress 中全局更改它们(您可以将其设置为 null 以隐藏进度条)。

如果没有提供行,也会显示加载状态。您可以使用 loading-state 道具来自定义 iconlabel,或者在 ui.table.default.loadingState 中全局更改它们(您可以将其设置为 null 以隐藏加载状态)。

ID姓名标题电子邮件角色

加载中...

<template>
  <UTable
    loading
    :loading-state="{ icon: 'i-heroicons-arrow-path-20-solid', label: 'Loading...' }"
    :progress="{ color: 'primary', animation: 'carousel' }"
    class="w-full"
    :columns="[{ key: 'id', label: 'ID' }, { key: 'name', label: 'Name' }, { key: 'title', label: 'Title' }, { key: 'email', label: 'Email' }, { key: 'role', label: 'Role' }]"
  />
</template>

这可以轻松地与 Nuxt useAsyncData 可组合函数一起使用。

<script setup lang="ts">
const columns = [...]

const { status, data: people } = await useLazyAsyncData('people', () => $fetch('/api/people'))
</script>

<template>
  <UTable :rows="people" :columns="columns" :loading="status === 'pending'" />
</template>

当没有结果时,将显示空状态。

使用 empty-state 道具来自定义 iconlabel,或者在 ui.table.default.emptyState 中全局更改它们。

您也可以将其设置为 null 以隐藏空状态。

ID姓名标题电子邮件角色

没有项目。

<template>
  <UTable
    :empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'No items.' }"
    class="w-full"
    :columns="[{ key: 'id', label: 'ID' }, { key: 'name', label: 'Name' }, { key: 'title', label: 'Title' }, { key: 'email', label: 'Email' }, { key: 'role', label: 'Role' }]"
  />
</template>

插槽

您可以使用插槽来自定义表格的标题和数据单元格。

<column>-header

使用 #<column>-header 插槽来自定义列的标题单元格。您将在插槽作用域中访问 columnsorton-sort 属性。

sort 属性是一个包含以下属性的对象。

  • field - 要排序的字段。
  • direction - 要排序的方向。可以是 ascdesc

on-sort 属性是一个函数,您可以调用它来对表格进行排序,并接受列作为参数。

虽然您可以像 可排序 部分中提到的那样自定义排序按钮,但您可以使用此插槽完全覆盖它的行为,例如使用自定义下拉菜单。

<column>-data

使用 #<column>-data 插槽来自定义列的数据单元格。您将在插槽作用域中访问 rowcolumngetRowData 属性。

例如,您可以在 Dropdown 组件内部创建一个用于操作的额外列,或者根据选择更改行的颜色。

姓名标题电子邮件角色
Lindsay Walton前端开发人员[email protected]成员
Courtney Henry设计师[email protected]管理员
Tom Cook产品总监[email protected]成员
Whitney Francis文案[email protected]管理员
Leonard Krasner高级设计师[email protected]所有者
Floyd Miles首席设计师[email protected]成员
<script setup lang="ts">
const columns = [{
  key: 'name',
  label: 'Name'
}, {
  key: 'title',
  label: 'Title'
}, {
  key: 'email',
  label: 'Email'
}, {
  key: 'role',
  label: 'Role'
}, {
  key: 'actions'
}]

const people = [{
  id: 1,
  name: 'Lindsay Walton',
  title: 'Front-end Developer',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 2,
  name: 'Courtney Henry',
  title: 'Designer',
  email: '[email protected]',
  role: 'Admin'
}, {
  id: 3,
  name: 'Tom Cook',
  title: 'Director of Product',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 4,
  name: 'Whitney Francis',
  title: 'Copywriter',
  email: '[email protected]',
  role: 'Admin'
}, {
  id: 5,
  name: 'Leonard Krasner',
  title: 'Senior Designer',
  email: '[email protected]',
  role: 'Owner'
}, {
  id: 6,
  name: 'Floyd Miles',
  title: 'Principal Designer',
  email: '[email protected]',
  role: 'Member'
}]

const items = row => [
  [{
    label: 'Edit',
    icon: 'i-heroicons-pencil-square-20-solid',
    click: () => console.log('Edit', row.id)
  }, {
    label: 'Duplicate',
    icon: 'i-heroicons-document-duplicate-20-solid'
  }], [{
    label: 'Archive',
    icon: 'i-heroicons-archive-box-20-solid'
  }, {
    label: 'Move',
    icon: 'i-heroicons-arrow-right-circle-20-solid'
  }], [{
    label: 'Delete',
    icon: 'i-heroicons-trash-20-solid'
  }]
]

const selected = ref([people[1]])
</script>

<template>
  <UTable v-model="selected" :rows="people" :columns="columns">
    <template #name-data="{ row }">
      <span :class="[selected.find(person => person.id === row.id) && 'text-primary-500 dark:text-primary-400']">{{ row.name }}</span>
    </template>

    <template #actions-data="{ row }">
      <UDropdown :items="items(row)">
        <UButton color="gray" variant="ghost" icon="i-heroicons-ellipsis-horizontal-20-solid" />
      </UDropdown>
    </template>
  </UTable>
</template>

expand-action

#expand-action 插槽允许您自定义可扩展表格行的扩展控制界面。此功能提供了一种灵活的方式来实现自定义扩展/折叠功能,同时仍然可以访问重要的行数据和状态。

用法

<template>
  <UTable>
    <template #expand-action="{ row, toggle, isExpanded }">
    <!-- Your custom expand action content -->
    </template>
  </UTable>
</template>

插槽属性

插槽提供三个关键属性

属性类型描述
row对象包含当前行的數據
toggle函数用于切换展开状态的函数
isExpanded布尔值当前行的展开状态
展开ID姓名标题电子邮件角色HasExpand
1Lindsay Walton前端开发人员[email protected]成员false
2Courtney Henry设计师[email protected]管理员true
{
  "id": 2,
  "name": "Courtney Henry",
  "title": "Designer",
  "email": "[email protected]",
  "role": "Admin",
  "hasExpand": true
}
3Tom Cook产品总监[email protected]成员false
4Whitney Francis文案[email protected]管理员true
5Leonard Krasner高级设计师[email protected]所有者false
6Floyd Miles首席设计师[email protected]成员true
<script setup lang='ts'>
const people = [{
  id: 1,
  name: 'Lindsay Walton',
  title: 'Front-end Developer',
  email: '[email protected]',
  role: 'Member',
  hasExpand: false
}, {
  id: 2,
  name: 'Courtney Henry',
  title: 'Designer',
  email: '[email protected]',
  role: 'Admin',
  hasExpand: true
}, {
  id: 3,
  name: 'Tom Cook',
  title: 'Director of Product',
  email: '[email protected]',
  role: 'Member',
  hasExpand: false
}, {
  id: 4,
  name: 'Whitney Francis',
  title: 'Copywriter',
  email: '[email protected]',
  role: 'Admin',
  hasExpand: true
}, {
  id: 5,
  name: 'Leonard Krasner',
  title: 'Senior Designer',
  email: '[email protected]',
  role: 'Owner',
  hasExpand: false
}, {
  id: 6,
  name: 'Floyd Miles',
  title: 'Principal Designer',
  email: '[email protected]',
  role: 'Member',
  hasExpand: true
}]

const expand = ref({
  openedRows: [people.find(v => v.hasExpand)],
  row: {}
})
</script>

<template>
  <UTable v-model:expand="expand" :rows="people">
    <template #expand="{ row }">
      <div class="p-4">
        <pre>{{ row }}</pre>
      </div>
    </template>
    <template #expand-action="{ row, isExpanded, toggle }">
      <UButton v-if="row.hasExpand" @click="toggle">
        {{ isExpanded ? 'collapse' : 'expand' }}
      </UButton>
    </template>
  </UTable>
</template>

loading-state

使用 #loading-state 插槽自定义加载状态。

姓名标题电子邮件角色
<script setup lang="ts">
const columns = [{
  key: 'name',
  label: 'Name'
}, {
  key: 'title',
  label: 'Title'
}, {
  key: 'email',
  label: 'Email'
}, {
  key: 'role',
  label: 'Role'
}, {
  key: 'actions'
}]

const people = []

const pending = ref(true)
</script>

<template>
  <UTable :rows="people" :columns="columns" :loading="pending">
    <template #loading-state>
      <div class="flex items-center justify-center h-32">
        <i class="loader --6" />
      </div>
    </template>
  </UTable>
</template>

<style scoped>
/* https://codepen.io/jenning/pen/YzNmzaV */

.loader {
  --color: rgb(var(--color-primary-400));
  --size-mid: 6vmin;
  --size-dot: 1.5vmin;
  --size-bar: 0.4vmin;
  --size-square: 3vmin;

  display: block;
  position: relative;
  width: 50%;
  display: grid;
  place-items: center;
}

.loader::before,
.loader::after {
  content: '';
  box-sizing: border-box;
  position: absolute;
}

/**
loader --6
**/
.loader.--6::before {
  width: var(--size-square);
  height: var(--size-square);
  background-color: var(--color);
  top: calc(50% - var(--size-square));
  left: calc(50% - var(--size-square));
  animation: loader-6 2.4s cubic-bezier(0, 0, 0.24, 1.21) infinite;
}

@keyframes loader-6 {

  0%,
  100% {
    transform: none;
  }

  25% {
    transform: translateX(100%);
  }

  50% {
    transform: translateX(100%) translateY(100%);
  }

  75% {
    transform: translateY(100%);
  }
}
</style>

empty-state

使用 #empty-state 插槽自定义空状态。

姓名标题电子邮件角色
这里没有人!
<script setup lang="ts">
const columns = [{
  key: 'name',
  label: 'Name'
}, {
  key: 'title',
  label: 'Title'
}, {
  key: 'email',
  label: 'Email'
}, {
  key: 'role',
  label: 'Role'
}, {
  key: 'actions'
}]

const people = []
</script>

<template>
  <UTable :rows="people" :columns="columns">
    <template #empty-state>
      <div class="flex flex-col items-center justify-center py-6 gap-3">
        <span class="italic text-sm">No one here!</span>
        <UButton label="Add people" />
      </div>
    </template>
  </UTable>
</template>

caption

使用 #caption 插槽自定义表格的标题。

ACME 的员工
姓名标题电子邮件角色
Lindsay Walton前端开发人员[email protected]成员
Courtney Henry设计师[email protected]管理员
Tom Cook产品总监[email protected]成员
Whitney Francis文案[email protected]管理员
Leonard Krasner高级设计师[email protected]所有者
Floyd Miles首席设计师[email protected]成员
<script setup lang="ts">
const columns = [{
  key: 'name',
  label: 'Name'
}, {
  key: 'title',
  label: 'Title'
}, {
  key: 'email',
  label: 'Email'
}, {
  key: 'role',
  label: 'Role'
}, {
  key: 'actions'
}]

const people = [{
  id: 1,
  name: 'Lindsay Walton',
  title: 'Front-end Developer',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 2,
  name: 'Courtney Henry',
  title: 'Designer',
  email: '[email protected]',
  role: 'Admin'
}, {
  id: 3,
  name: 'Tom Cook',
  title: 'Director of Product',
  email: '[email protected]',
  role: 'Member'
}, {
  id: 4,
  name: 'Whitney Francis',
  title: 'Copywriter',
  email: '[email protected]',
  role: 'Admin'
}, {
  id: 5,
  name: 'Leonard Krasner',
  title: 'Senior Designer',
  email: '[email protected]',
  role: 'Owner'
}, {
  id: 6,
  name: 'Floyd Miles',
  title: 'Principal Designer',
  email: '[email protected]',
  role: 'Member'
}]
</script>

<template>
  <UTable :rows="people" :columns="columns">
    <template #caption>
      <caption>Employees of ACME</caption>
    </template>
  </UTable>
</template>

属性

sort
{ column: string; direction: "asc" | "desc"; }
{}
ui
{ wrapper?: string; base?: string; divide?: string; thead?: string; tbody?: string; caption?: string; tr?: DeepPartial<{ base: string; selected: string; expanded: string; active: string; }, any>; ... 7 more ...; default?: DeepPartial<...>; } & { ...; } & { ...; }
{}
caption
字符串
null
progress
{ color: string; animation: "carousel" | "carousel-inverse" | "swing" | "elastic"; }
config.default.progress
modelValue
unknown[]
null
by
字符串 | 函数
defaultComparator
rows
TableRow[]
[]
loadingState
{ icon: string; label: string; }
config.default.loadingState
emptyState
{ icon: string; label: string; }
config.default.emptyState
expand
Expanded<TableRow>
null
columns
TableColumn[]
null
columnAttribute
字符串
"label"
sortMode
"auto" | "manual"
"auto"
sortButton
按钮
config.default.sortButton as Button
sortAscIcon
字符串
config.default.sortAscIcon
sortDescIcon
字符串
config.default.sortDescIcon
expandButton
按钮
config.default.expandButton as Button
加载中
布尔值
false
multipleExpand
布尔值
true

配置

{
  wrapper: 'relative overflow-x-auto',
  base: 'min-w-full table-fixed',
  divide: 'divide-y divide-gray-300 dark:divide-gray-700',
  thead: 'relative',
  tbody: 'divide-y divide-gray-200 dark:divide-gray-800',
  caption: 'sr-only',
  tr: {
    base: '',
    selected: 'bg-gray-50 dark:bg-gray-800/50',
    expanded: 'bg-gray-50 dark:bg-gray-800/50',
    active: 'hover:bg-gray-50 dark:hover:bg-gray-800/50 cursor-pointer'
  },
  th: {
    base: 'text-left rtl:text-right',
    padding: 'px-4 py-3.5',
    color: 'text-gray-900 dark:text-white',
    font: 'font-semibold',
    size: 'text-sm'
  },
  td: {
    base: 'whitespace-nowrap',
    padding: 'px-4 py-4',
    color: 'text-gray-500 dark:text-gray-400',
    font: '',
    size: 'text-sm'
  },
  checkbox: {
    padding: 'ps-4'
  },
  loadingState: {
    wrapper: 'flex flex-col items-center justify-center flex-1 px-6 py-14 sm:px-14',
    label: 'text-sm text-center text-gray-900 dark:text-white',
    icon: 'w-6 h-6 mx-auto text-gray-400 dark:text-gray-500 mb-4 animate-spin'
  },
  emptyState: {
    wrapper: 'flex flex-col items-center justify-center flex-1 px-6 py-14 sm:px-14',
    label: 'text-sm text-center text-gray-900 dark:text-white',
    icon: 'w-6 h-6 mx-auto text-gray-400 dark:text-gray-500 mb-4'
  },
  expand: {
    icon: 'transform transition-transform duration-200'
  },
  progress: {
    wrapper: 'absolute inset-x-0 -bottom-[0.5px] p-0'
  },
  default: {
    sortAscIcon: 'i-heroicons-bars-arrow-up-20-solid',
    sortDescIcon: 'i-heroicons-bars-arrow-down-20-solid',
    sortButton: {
      icon: 'i-heroicons-arrows-up-down-20-solid',
      trailing: true,
      square: true,
      color: 'gray',
      variant: 'ghost',
      class: '-m-1.5'
    },
    expandButton: {
      icon: 'i-heroicons-chevron-down',
      color: 'gray',
      variant: 'ghost',
      size: 'xs',
      class: '-my-1.5 align-middle'
    },
    checkbox: {
      color: 'primary'
    },
    progress: {
      color: 'primary',
      animation: 'carousel'
    },
    loadingState: {
      icon: 'i-heroicons-arrow-path-20-solid',
      label: 'Loading...'
    },
    emptyState: {
      icon: 'i-heroicons-circle-stack-20-solid',
      label: 'No items.'
    }
  }
}

示例

这是一个带有所有功能的表格组件示例。

待办事项

每页行数
操作
1delectus aut autem进行中
2quis ut nam facilis et officia qui进行中
3fugiat veniam minus进行中
4et porro tempora已完成
5laboriosam mollitia et enim quasi adipisci quia provident illum进行中
6qui ullam ratione quibusdam voluptatem quia omnis进行中
7illo expedita consequatur quia in进行中
8quo adipisci enim quam ut ab已完成
9molestiae perspiciatis ipsa进行中
10illo est ratione doloremque quia maiores aut已完成
显示 110200 个结果
看看这个组件!