Documentación/Resumen
Tabla de datos
Una tabla de Nuxt UI con 2000 tareas, virtualizada y con búsqueda, ordenada arrastrando sus filas por sus asas.
Esta página la ha traducido una IA y puede contener imprecisiones. Leer el original en inglés
Cargando la demo…
<script setup lang="ts">
import { DnDProvider } from '@vue-dnd-kit/core';
import TaskTable from './TaskTable.vue';
</script>
<template>
<!-- The row in hand: a table row can't have a shadow, so its overlay content has it. -->
<DnDProvider overlay-class="overflow-hidden rounded-md bg-default shadow-xl ring ring-accented">
<TaskTable />
</DnDProvider>
</template>El UTable de Nuxt UI renderiza la tabla, sus filas y su virtualizador: solo las filas que están en
pantalla están en el DOM. Vue DnD Kit las ordena. La tabla es la de la biblioteca tal como viene,
con sus slots y sus clases ui; no se reescribe nada de ella.
Qué observar
TaskTable.vue: la lista ordenable es el<tbody>de la tabla, que se encuentra a través deltableRefque exponeUTable. La tabla recibe el borrador de la lista como sudata, así que las filas se mueven mientras arrastras, yget-row-idles da como clave la tarea, igual que hace la lista.axis: 'y'mantiene el arrastre en su columna, yrestrictToFirstScrollableAncestor, dentro de la tabla: su contenedor desplazable es el primer elemento desplazable alrededor de las filas. Amplía la demo: la tabla llena la pantalla.RowGrip.vue:UTablerenderiza las filas, así que ningún componente tuyo es una fila. El asa de la primera celda (el slot#grip-cell) convierte en el ítem la fila que la rodea, y es su asa (handle).- La búsqueda es el
filterde la lista: la tabla muestra las tareas que coinciden, y un drop escribe de vuelta el array entero, con las tareas ocultas donde estaban. tasks.ts: 2000 tareas en unshallowRef: la biblioteca nunca mira dentro de ellas.
Una fila que renderiza la tabla
El asa llama a makeSortableItem con un getter para la fila: el <tr> que la rodea, una vez
renderizado. Como es el handle, el asa recibe el foco y los atributos ARIA, y el resto de la fila
queda libre para los clics y la selección de texto.
const grip = useTemplateRef<HTMLElement>('grip');
makeSortableItem(() => grip.value?.closest('tr') ?? null, {
id: () => props.task.id,
handle: grip,
label: () => props.task.title,
});
<UTable ref="table" :data="items" :get-row-id="(task: Task) => task.id" …>
<template #grip-cell="{ row }">
<RowGrip :task="row.original" />
</template>
</UTable>
El overlay es la copia de la fila que hace la biblioteca, en una tabla propia con los anchos de las
celdas. Una fila de tabla no dibuja sombra, así que el overlay-class del provider le da una al
contenido del overlay, con el fondo de la tabla y un anillo. Las clases ui de la fila tiñen su
sitio mientras viaja (data-[dnd-placeholder]:bg-primary/5).
<DnDProvider overlay-class="overflow-hidden rounded-md bg-default shadow-xl ring ring-accented">
<TaskTable />
</DnDProvider>
Filas virtualizadas
virtualize le da a la tabla TanStack Virtual: se renderizan las filas en pantalla y 8 más a su
alrededor (overscan), entre dos filas espaciadoras.
<UTable
:data="items"
:watch-options="{ deep: false }"
:virtualize="{ estimateSize: 45, overscan: 8, onChange: () => captureLayout() }"
class="min-h-0 flex-1"
/>
estimateSizees una primera estimación: el virtualizador mide cada fila al renderizarla. Una medición mueve las filas que hay debajo, yonChangellama alcaptureLayout()de la lista, así que la biblioteca anima ese movimiento durante un arrastre en lugar de dejar que salte.- La tabla es el contenedor desplazable, y la fila en la mano se queda dentro de ella: cerca de su borde superior o inferior, un arrastre la desplaza, y las filas nuevas se renderizan a medida que entran a la vista.
- El borrador es un array nuevo después de cada movimiento, así que la tabla no necesita observar su
interior (
deep: false). - Desplázate lejos de la fila que sostienes, y sale del rango renderizado y se desmonta. El arrastre
continúa: el overlay la sigue mostrando, y aterriza donde la pone el borrador. Una lista virtual
propia puede mantenerla montada con
rangeExtractor(consulta Listas virtuales). Una tabla coloca sus filas entre filas espaciadoras, donde una fila renderizada lejos de las demás las apartaría, así que esta la deja ir.
Buscar y luego arrastrar
const { items, captureLayout } = makeSortableList(() => table.value?.tableRef?.tBodies[0] ?? null, {
items: tasks,
filter: (task) => {
const text = query.value.trim().toLowerCase();
return !text || `${task.id} ${task.title} ${task.assignee}`.toLowerCase().includes(text);
},
axis: 'y',
modifiers: [restrictToFirstScrollableAncestor],
label: 'Tasks',
});
Busca «Mia», mueve una de sus tareas encima de otra y luego vacía la búsqueda: sus tareas están en el
nuevo orden, y todas las demás tareas siguen donde estaban. El e.to.index del drop cuenta las
filas mostradas; e.result contiene el array entero.
- La fila. Un slot que renderiza la fila entera (
#itemde Vuetify,#bodyde Quasar) te da su elemento: conviértelo en el ítem. Donde solo recibes celdas (el#bodyde unaColumnde PrimeVue, el slot por defecto de una columna de Element Plus, elrenderde Naive UI), pon un asa en una de ellas y convierte suclosest('tr')en el ítem, como aquí. - La lista. El
<tbody>dentro del elemento raíz de la tabla: una ref de plantilla en la tabla te da el componente, y su$el, el elemento. - Las claves y los datos. Da a las filas como clave tu id (
item-value,row-key,dataKey) y pásale a la tabla el borrador de la lista como sus datos. - Sin su propia ordenación. Prescinde de la reordenación de filas propia de la tabla y de su ordenación por columnas: el orden es el de la lista.
- Las tablas virtuales colocan sus filas entre espaciadores o en cajas absolutas: las dos cosas funcionan, y un arrastre sobrevive a que su fila se desmonte.
@nuxt/ui/vite, Tailwind CSS y UApp alrededor del
ejemplo. En una app de Nuxt con el módulo @nuxt/ui, copia la carpeta y renderiza index.vue en
una página.Teclado y lectores de pantalla
Llega con Tab al asa de una tarea y pulsa Space para agarrar la fila.
ArrowUp y ArrowDown la mueven, Space la suelta y
Escape la devuelve a su sitio. Las filas tienen un label, y la lista también: los
lectores de pantalla oyen «Fix the login form dropped at position 3 of 2000 in Tasks.», no claves.
Más información: Listas virtuales · Mostrar solo algunos ítems · Estilos: Tailwind y kits de UI · Accesibilidad