docs(table): add infinite scroll example (#3656)

Co-authored-by: Hadrien Hartstein <hadrien@emagma.fr>
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
This commit is contained in:
Kheuval
2025-04-22 16:14:59 +02:00
committed by GitHub
parent 122e8ac8f4
commit e25aa78050
4 changed files with 108 additions and 6 deletions

View File

@@ -0,0 +1,88 @@
<script setup lang="ts">
import type { TableColumn } from '@nuxt/ui'
import { useInfiniteScroll } from '@vueuse/core'
const UAvatar = resolveComponent('UAvatar')
type User = {
id: number
firstName: string
username: string
email: string
image: string
}
type UserResponse = {
users: User[]
total: number
skip: number
limit: number
}
const skip = ref(0)
const { data, status, execute } = await useFetch('https://dummyjson.com/users?limit=10&select=firstName,username,email,image', {
key: 'table-users-infinite-scroll',
params: { skip },
transform: (data?: UserResponse) => {
return data?.users
},
lazy: true,
immediate: false
})
const columns: TableColumn<User>[] = [{
accessorKey: 'id',
header: 'ID'
}, {
accessorKey: 'image',
header: 'Avatar',
cell: ({ row }) => h(UAvatar, { src: row.original.image })
}, {
accessorKey: 'firstName',
header: 'First name'
}, {
accessorKey: 'email',
header: 'Email'
}, {
accessorKey: 'username',
header: 'Username'
}]
const users = ref<User[]>([])
watch(data, () => {
users.value = [
...users.value,
...(data.value || [])
]
})
execute()
const table = useTemplateRef<ComponentPublicInstance>('table')
onMounted(() => {
useInfiniteScroll(table.value?.$el, () => {
skip.value += 10
}, {
distance: 200,
canLoadMore: () => {
return status.value !== 'pending'
}
})
})
</script>
<template>
<div class="w-full">
<UTable
ref="table"
:data="users"
:columns="columns"
:loading="status === 'pending'"
sticky
class="flex-1 h-80"
/>
</div>
</template>

View File

@@ -251,8 +251,6 @@ When `type="multiple"`, ensure to pass an array to the `default-value` prop or t
Use the [`useSortable`](https://vueuse.org/integrations/useSortable/) composable from [`@vueuse/integrations`](https://vueuse.org/integrations/README.html) to enable drag and drop functionality on the Accordion. This integration wraps [Sortable.js](https://sortablejs.github.io/Sortable/) to provide a seamless drag and drop experience.
The `useSortable` composable accepts various options, see the [useSortable](https://vueuse.org/integrations/useSortable/#usage) documentation for more examples.
::component-example
---
name: 'accordion-drag-and-drop-example'

View File

@@ -444,12 +444,24 @@ class: '!p-0'
---
::
### With infinite scroll
If you use server-side pagination, you can use the [`useInfiniteScroll`](https://vueuse.org/core/useInfiniteScroll/#useinfinitescroll) composable to load more data when scrolling.
::component-example
---
prettier: true
collapse: true
overflowHidden: true
name: 'table-infinite-scroll-example'
class: '!p-0'
---
::
### With drag and drop
Use the [`useSortable`](https://vueuse.org/integrations/useSortable/) composable from [`@vueuse/integrations`](https://vueuse.org/integrations/README.html) to enable drag and drop functionality on the Table. This integration wraps [Sortable.js](https://sortablejs.github.io/Sortable/) to provide a seamless drag and drop experience.
The `useSortable` composable accepts various options, see the [useSortable](https://vueuse.org/integrations/useSortable/#usage) documentation for more examples.
::note
Since the table ref doesn't expose the tbody element, add a unique class to it via the `:ui` prop to target it with `useSortable` (e.g. `:ui="{ tbody: 'my-table-tbody' }"`).
::
@@ -508,6 +520,7 @@ This will give you access to the following:
| Name | Type |
| ---- | ---- |
| `tableRef`{lang="ts-type"} | `Ref<HTMLTableElement \| null>`{lang="ts-type"} |
| `tableApi`{lang="ts-type"} | [`Ref<Table \| null>`{lang="ts-type"}](https://tanstack.com/table/latest/docs/api/core/table#table-api) |
## Theme

View File

@@ -167,7 +167,7 @@ export type TableSlots<T> = {
</script>
<script setup lang="ts" generic="T extends TableData">
import { computed } from 'vue'
import { computed, ref } from 'vue'
import { Primitive } from 'reka-ui'
import { upperFirst } from 'scule'
import { FlexRender, getCoreRowModel, getFilteredRowModel, getSortedRowModel, getExpandedRowModel, useVueTable } from '@tanstack/vue-table'
@@ -206,6 +206,8 @@ const groupingState = defineModel<GroupingState>('grouping', { default: [] })
const expandedState = defineModel<ExpandedState>('expanded', { default: {} })
const paginationState = defineModel<PaginationState>('pagination', { default: {} })
const tableRef = ref<HTMLTableElement>()
const tableApi = useVueTable({
...reactiveOmit(props, 'as', 'data', 'columns', 'caption', 'sticky', 'loading', 'loadingColor', 'loadingAnimation', 'class', 'ui'),
data,
@@ -303,13 +305,14 @@ function handleRowSelect(row: TableRow<T>, e: Event) {
}
defineExpose({
tableRef,
tableApi
})
</script>
<template>
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })">
<table :class="ui.base({ class: [props.ui?.base] })">
<table ref="tableRef" :class="ui.base({ class: [props.ui?.base] })">
<caption v-if="caption || !!slots.caption" :class="ui.caption({ class: [props.ui?.caption] })">
<slot name="caption">
{{ caption }}