Documentação/Visão geral
Tabela de dados
Uma tabela do Nuxt UI com 2.000 tarefas, virtualizada e pesquisável, ordenada arrastando as linhas pelas alças.
Esta página foi traduzida por IA e pode conter imprecisões. Ler o original em inglês
Carregando a 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>O UTable do Nuxt UI renderiza a tabela, as linhas e o virtualizador dela: só as linhas que estão na
tela ficam no DOM. O Vue DnD Kit as ordena. A tabela é a da biblioteca do jeito que vem, com os seus
slots e as suas classes ui; nada dela é reescrito.
O que observar
TaskTable.vue: a lista ordenável é o<tbody>da tabela, encontrado pelotableRefque oUTableexpõe. A tabela recebe o rascunho da lista comodata, então as linhas se movem enquanto você arrasta, eget-row-iddá às linhas a key da tarefa, como a lista faz.axis: 'y'mantém o arraste na coluna dele, erestrictToFirstScrollableAncestor, dentro da tabela: o contêiner de rolagem dela é o primeiro elemento rolável em volta das linhas. Expanda a demo: a tabela preenche a tela.RowGrip.vue: oUTablerenderiza as linhas, então nenhum componente seu é uma linha. A alça na primeira célula (o slot#grip-cell) torna a linha em volta dela o item, e é o handle dele.- A busca é o
filterda lista: a tabela mostra as tarefas que correspondem, e um drop grava de volta o array inteiro, com as tarefas ocultas onde estavam. tasks.ts: 2.000 tarefas em umshallowRef: a biblioteca nunca olha dentro delas.
Uma linha que a tabela renderiza
A alça chama makeSortableItem com um getter para a linha: o <tr> em volta dela, depois de
renderizado. Como handle, a alça recebe o foco e os atributos ARIA, e o resto da linha fica livre
para cliques e seleção 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>
O overlay é a cópia da linha feita pela biblioteca, em uma tabela própria com as larguras das
células. Uma linha de tabela não desenha sombra, então o overlay-class do provider dá uma ao
conteúdo do overlay, com o fundo da tabela e um anel. As classes ui da linha tingem o lugar dela
enquanto ela viaja (data-[dnd-placeholder]:bg-primary/5).
<DnDProvider overlay-class="overflow-hidden rounded-md bg-default shadow-xl ring ring-accented">
<TaskTable />
</DnDProvider>
Linhas virtualizadas
virtualize dá à tabela o TanStack Virtual: as linhas na tela e mais 8 em volta delas (overscan)
são renderizadas, entre duas linhas espaçadoras.
<UTable
:data="items"
:watch-options="{ deep: false }"
:virtualize="{ estimateSize: 45, overscan: 8, onChange: () => captureLayout() }"
class="min-h-0 flex-1"
/>
estimateSizeé um primeiro palpite: o virtualizador mede cada linha conforme a renderiza. Uma medição move as linhas abaixo dela, eonChangechama ocaptureLayout()da lista, então a biblioteca anima esse movimento durante um arraste em vez de deixá-lo pular.- A tabela é o contêiner de rolagem, e a linha na mão fica dentro dela: perto da borda de cima ou de baixo, um arraste a rola, e novas linhas são renderizadas conforme entram na tela.
- O rascunho é um array novo depois de cada movimento, então a tabela não precisa observar dentro
dele (
deep: false). - Role para longe da linha que você está segurando, e ela sai do intervalo renderizado e é
desmontada. O arraste continua: o overlay ainda a mostra, e ela pousa onde o rascunho a coloca. Uma
lista virtual sua pode mantê-la montada com
rangeExtractor(veja Listas virtuais). Uma tabela dispõe as linhas entre linhas espaçadoras, onde uma linha renderizada longe das outras as empurraria para o lado, então esta a deixa ir.
Pesquise, depois arraste
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',
});
Pesquise "Mia", mova uma das tarefas dela para cima de outra e depois limpe a busca: as tarefas dela
estão na nova ordem, e todas as outras tarefas estão onde estavam. O e.to.index do drop conta as
linhas mostradas; e.result contém o array inteiro.
- A linha. Um slot que renderiza a linha inteira (
#itemdo Vuetify,#bodydo Quasar) dá a você o elemento dela: torne-o o item. Onde você só recebe células (o#bodyde umaColumndo PrimeVue, o slot padrão de uma coluna do Element Plus, orenderdo Naive UI), coloque uma alça em uma delas e torne oclosest('tr')dela o item, como aqui. - A lista. O
<tbody>dentro do elemento raiz da tabela: um template ref na tabela dá a você o componente, e o$eldele, o elemento. - As keys e os dados. Dê às linhas a key do seu id (
item-value,row-key,dataKey) e passe para a tabela o rascunho da lista como os dados dela. - Ordenação própria desligada. Deixe de fora a reordenação de linhas da própria tabela e a ordenação por colunas: a ordem é a da lista.
- Tabelas virtuais posicionam as linhas entre espaçadores ou em caixas absolutas: os dois funcionam, e um arraste sobrevive à desmontagem da sua linha.
@nuxt/ui/vite, o Tailwind CSS e UApp em volta do
exemplo. Em um app Nuxt com o módulo @nuxt/ui, copie a pasta e renderize index.vue em uma
página.Teclado e leitores de tela
Chegue com Tab à alça de uma tarefa e pressione Space para pegar a linha.
ArrowUp e ArrowDown a movem, Space a solta e
Escape a devolve ao lugar. As linhas têm um label, e a lista também: os leitores de
tela ouvem "Fix the login form dropped at position 3 of 2000 in Tasks.", não keys.
Leia mais: Listas virtuais · Mostrar parte dos itens · Estilização: Tailwind e kits de UI · Acessibilidade