mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-31 04:07:56 +01:00
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:
@@ -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>
|
||||||
@@ -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.
|
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
|
::component-example
|
||||||
---
|
---
|
||||||
name: 'accordion-drag-and-drop-example'
|
name: 'accordion-drag-and-drop-example'
|
||||||
|
|||||||
@@ -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
|
### 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.
|
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
|
::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' }"`).
|
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 |
|
| 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) |
|
| `tableApi`{lang="ts-type"} | [`Ref<Table \| null>`{lang="ts-type"}](https://tanstack.com/table/latest/docs/api/core/table#table-api) |
|
||||||
|
|
||||||
## Theme
|
## Theme
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ export type TableSlots<T> = {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script setup lang="ts" generic="T extends TableData">
|
<script setup lang="ts" generic="T extends TableData">
|
||||||
import { computed } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { Primitive } from 'reka-ui'
|
import { Primitive } from 'reka-ui'
|
||||||
import { upperFirst } from 'scule'
|
import { upperFirst } from 'scule'
|
||||||
import { FlexRender, getCoreRowModel, getFilteredRowModel, getSortedRowModel, getExpandedRowModel, useVueTable } from '@tanstack/vue-table'
|
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 expandedState = defineModel<ExpandedState>('expanded', { default: {} })
|
||||||
const paginationState = defineModel<PaginationState>('pagination', { default: {} })
|
const paginationState = defineModel<PaginationState>('pagination', { default: {} })
|
||||||
|
|
||||||
|
const tableRef = ref<HTMLTableElement>()
|
||||||
|
|
||||||
const tableApi = useVueTable({
|
const tableApi = useVueTable({
|
||||||
...reactiveOmit(props, 'as', 'data', 'columns', 'caption', 'sticky', 'loading', 'loadingColor', 'loadingAnimation', 'class', 'ui'),
|
...reactiveOmit(props, 'as', 'data', 'columns', 'caption', 'sticky', 'loading', 'loadingColor', 'loadingAnimation', 'class', 'ui'),
|
||||||
data,
|
data,
|
||||||
@@ -303,13 +305,14 @@ function handleRowSelect(row: TableRow<T>, e: Event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
|
tableRef,
|
||||||
tableApi
|
tableApi
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Primitive :as="as" :class="ui.root({ class: [props.class, props.ui?.root] })">
|
<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] })">
|
<caption v-if="caption || !!slots.caption" :class="ui.caption({ class: [props.ui?.caption] })">
|
||||||
<slot name="caption">
|
<slot name="caption">
|
||||||
{{ caption }}
|
{{ caption }}
|
||||||
|
|||||||
Reference in New Issue
Block a user