Dokumentation/Übersicht
Datentabelle
Eine Nuxt-UI-Tabelle mit 2.000 Aufgaben, virtualisiert und durchsuchbar, sortiert durch Ziehen ihrer Zeilen an den Griffen.
Diese Seite wurde von KI übersetzt und kann Ungenauigkeiten enthalten. Englisches Original lesen
Demo wird geladen…
<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>UTable aus Nuxt UI rendert die Tabelle, ihre Zeilen und ihren Virtualizer: Nur die Zeilen auf dem
Bildschirm sind im DOM. Vue DnD Kit sortiert sie. Die Tabelle ist die der Bibliothek, so wie sie
kommt, mit ihren Slots und ihren ui-Klassen; nichts daran wird neu geschrieben.
Worauf du achten solltest
TaskTable.vue: Die sortierbare Liste ist das<tbody>der Tabelle, gefunden über dietableRef, dieUTablebereitstellt. Die Tabelle bekommt den Entwurf der Liste alsdata, also bewegen sich die Zeilen, während du ziehst, undget-row-idgibt ihnen die Aufgabe als Schlüssel, wie es die Liste tut.axis: 'y'hält den Drag in seiner Spalte undrestrictToFirstScrollableAncestorin der Tabelle: Ihr Scroll-Container ist das erste scrollbare Element um die Zeilen. Klappe die Demo auf: Die Tabelle füllt den Bildschirm.RowGrip.vue:UTablerendert die Zeilen, also ist keine deiner Komponenten eine Zeile. Der Griff in der ersten Zelle (der Slot#grip-cell) macht die Zeile um ihn herum zum sortierbaren Element und ist ihr Handle.- Die Suche ist der
filterder Liste: Die Tabelle zeigt die passenden Aufgaben, und ein Drop schreibt das ganze Array zurück, die ausgeblendeten Aufgaben dort, wo sie waren. tasks.ts: 2.000 Aufgaben in einemshallowRef: Die Bibliothek schaut nie in sie hinein.
Eine Zeile, die die Tabelle rendert
Der Griff ruft makeSortableItem mit einem Getter für die Zeile auf: das <tr> um ihn herum, sobald
es gerendert ist. Als Handle bekommt der Griff den Fokus und die ARIA-Attribute, und der Rest der
Zeile bleibt frei für Klicks und Textauswahl.
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>
Das Overlay ist die Kopie der Zeile, die die Bibliothek anlegt, in einer eigenen Tabelle mit den
Breiten der Zellen. Eine Tabellenzeile zeichnet keinen Schatten, also gibt die overlay-class des
Providers dem Inhalt des Overlays einen, mit dem Hintergrund der Tabelle und einem Ring. Die
ui-Klassen der Zeile färben ihren Platz, während sie unterwegs ist
(data-[dnd-placeholder]:bg-primary/5).
<DnDProvider overlay-class="overflow-hidden rounded-md bg-default shadow-xl ring ring-accented">
<TaskTable />
</DnDProvider>
Virtualisierte Zeilen
virtualize gibt der Tabelle TanStack Virtual: Die Zeilen auf dem Bildschirm und 8 weitere um sie
herum (overscan) werden gerendert, zwischen zwei Platzhalterzeilen.
<UTable
:data="items"
:watch-options="{ deep: false }"
:virtualize="{ estimateSize: 45, overscan: 8, onChange: () => captureLayout() }"
class="min-h-0 flex-1"
/>
estimateSizeist eine erste Schätzung: Der Virtualizer misst jede Zeile, wenn er sie rendert. Eine Messung verschiebt die Zeilen darunter, undonChangeruftcaptureLayout()der Liste auf, sodass die Bibliothek diese Verschiebung während eines Drags animiert, statt sie springen zu lassen.- Die Tabelle ist der Scroll-Container, und die Zeile in der Hand bleibt in ihr: Nahe ihrem oberen oder unteren Rand scrollt ein Drag sie, und neue Zeilen werden gerendert, sobald sie ins Bild kommen.
- Der Entwurf ist nach jeder Bewegung ein neues Array, also muss die Tabelle nicht in ihn
hineinschauen (
deep: false). - Scrolle weit weg von der Zeile, die du hältst, und sie verlässt den gerenderten Bereich und wird
ausgehängt. Der Drag geht weiter: Das Overlay zeigt sie weiterhin, und sie landet dort, wo der
Entwurf sie hinsetzt. Eine eigene virtuelle Liste kann sie mit
rangeExtractoreingehängt halten (siehe Virtuelle Listen). Eine Tabelle legt ihre Zeilen zwischen Platzhalterzeilen an, wo eine weit entfernt von den anderen gerenderte Zeile sie beiseiteschieben würde, also lässt diese sie gehen.
Suchen, dann ziehen
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',
});
Suche nach „Mia“, schiebe eine ihrer Aufgaben über eine andere und leere dann die Suche: Ihre
Aufgaben stehen in der neuen Reihenfolge, und jede andere Aufgabe ist dort, wo sie war. e.to.index
des Drops zählt die angezeigten Zeilen; e.result enthält das ganze Array.
- Die Zeile. Ein Slot, der die ganze Zeile rendert (
#itemin Vuetify,#bodyin Quasar), gibt dir ihr Element: Mach es zum sortierbaren Element. Wo du nur Zellen bekommst (der#bodyeiner PrimeVue-Column, der Default-Slot einer Element-Plus-Spalte,renderin Naive UI), setze einen Griff in eine davon und mach dessenclosest('tr')zum sortierbaren Element, wie hier. - Die Liste. Das
<tbody>im Wurzelelement der Tabelle: Ein Template-Ref auf der Tabelle gibt dir die Komponente und ihr$eldas Element. - Die Schlüssel und die Daten. Gib den Zeilen deine ID als Schlüssel (
item-value,row-key,dataKey) und der Tabelle den Entwurf der Liste als Daten. - Ihre eigene Sortierung aus. Lass das eingebaute Umsortieren von Zeilen der Tabelle und ihre Spaltensortierung weg: Die Reihenfolge ist die der Liste.
- Virtuelle Tabellen platzieren ihre Zeilen zwischen Platzhaltern oder in absolut positionierten Boxen: Beides funktioniert, und ein Drag übersteht, dass seine Zeile ausgehängt wird.
@nuxt/ui/vite, Tailwind CSS und UApp um
das Beispiel. In einer Nuxt-App mit dem Modul @nuxt/ui kopierst du den Ordner und renderst
index.vue auf einer Seite.Tastatur und Screenreader
Springe mit Tab zum Griff einer Aufgabe und drücke Space, um die Zeile aufzunehmen.
ArrowUp und ArrowDown bewegen sie, Space legt sie ab,
Escape bringt sie zurück. Die Zeilen haben ein label und die Liste auch:
Screenreader hören „Fix the login form dropped at position 3 of 2000 in Tasks.“, keine Schlüssel.
Mehr dazu: Virtuelle Listen · Nur einen Teil der Elemente zeigen · Styling: Tailwind und UI-Kits · Barrierefreiheit