Vitral 0.2
Dados

VirtualScroller

Renderiza só os itens perto da viewport, então cem mil linhas custam o mesmo que uma tela cheia, com carregamento sob demanda.

Importação

main.ts
import { VirtualScroller } from '@vitral/vue';

Cem mil linhas

Item #0
Item #1
Item #2
Item #3
Item #4
Item #5
Item #6
Item #7
Item #8
Item #9
Item #10
<script setup lang="ts">import { Button, VirtualScroller } from '@vitral/vue';import { ref } from 'vue'; const items = Array.from({ length: 100000 }, (_, i) => ({ id: i, name: `Item #${i}` })); const scroller = ref<InstanceType<typeof VirtualScroller> | null>(null);</script> <template>    <Button label="Jump to #50,000" severity="secondary" style="align-self: flex-start" @click="scroller?.scrollToIndex(50000)" />    <VirtualScroller ref="scroller" :items="items" :item-size="40" scroll-height="16rem" data-key="id" aria-label="Items" style="border: 1px solid var(--vt-content-border-color)">        <template #item="{ item, options }">            <div :style="{ height: '40px', display: 'flex', alignItems: 'center', padding: '0 1rem', background: options.odd ? 'var(--vt-content-hover-background)' : undefined }">                {{ (item as { name: string }).name }}            </div>        </template>    </VirtualScroller></template>

Horizontal

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script setup lang="ts">import { VirtualScroller } from '@vitral/vue'; const columns = Array.from({ length: 1000 }, (_, i) => i);</script> <template>    <VirtualScroller :items="columns" :item-size="72" orientation="horizontal" scroll-width="100%" style="height: 5rem; border: 1px solid var(--vt-content-border-color)" aria-label="Columns">        <template #item="{ item }">            <div style="display: flex; align-items: center; justify-content: center; height: 100%; border-inline-end: 1px solid var(--vt-content-border-color)">{{ item }}</div>        </template>    </VirtualScroller></template>

Sob demanda

Row 0…
Row 1…
Row 2…
Row 3…
Row 4…
Row 5…
Row 6…
Row 7…
Row 8…
Row 9…
Row 10…
Carregando…
<script setup lang="ts">import { VirtualScroller } from '@vitral/vue';import { ref } from 'vue'; const lazyItems = ref<(string | null)[]>(Array.from({ length: 5000 }, () => null));const loading = ref(false);function load({ first, last }: { first: number; last: number }) {    loading.value = true;    setTimeout(() => {        const next = [...lazyItems.value];        for (let i = first; i < last; i++) next[i] = `Loaded row ${i}`;        lazyItems.value = next;        loading.value = false;    }, 400);}</script> <template>    <VirtualScroller :items="lazyItems" :item-size="36" scroll-height="14rem" lazy :loading="loading" :delay="150" aria-label="Lazy rows" style="width: 100%; border: 1px solid var(--vt-content-border-color)" @lazy-load="load">        <template #item="{ item, options }">            <div style="height: 36px; display: flex; align-items: center; padding: 0 1rem">{{ item ?? `Row ${options.index}…` }}</div>        </template>    </VirtualScroller></template>

API

Lido de packages/vue/src/components/VirtualScroller/types.ts, então diz o que o componente aceita de fato.

Props

NomeTipoDescrição
itemsany[]Todos os itens; só os próximos da área visível são renderizados.
itemSize *numberA altura de um item (ou largura, na horizontal) em pixels.
orientation'vertical' | 'horizontal'Rola na `'vertical'` (o padrão) ou na `'horizontal'`.
scrollHeightstringA altura (ou largura) do contêiner, quando o pai não define uma.
scrollWidthstring—
numToleratedItemsnumberItens renderizados além de cada borda da área visível. O padrão é meia área visível.
lazybooleanPede os itens à medida que entram na tela (`lazy-load`) em vez de tê-los todos.
loadingbooleanMostra o indicador de carregamento sobre a lista.
disabledbooleanRenderiza todos os itens, como faria um contêiner comum.
delaynumberMilissegundos a esperar depois que a rolagem para antes de `lazy-load`. O padrão é 0.
dataKeystringUm campo-chave para os itens renderizados; sem ele, usa-se o índice.

Mais pt, dt e unstyled de BaseProps; veja pass-through e modo sem estilo.

Emits

EventoPayloadDescrição
scroll-index-changeevent: { first: number; last: number }—
lazy-loadevent: { first: number; last: number }No modo lazy, o intervalo de itens que o scroller está prestes a mostrar.
scrollevent: Event—

Slots

NomeProps do slotDescrição
item(props: { item: unknown; options: VirtualScrollerItemOptions })—
content(props: { items: unknown[]; first: number; last: number; styleOffset: Record<string, string>; itemSize: number })Substitui por completo o intervalo renderizado, para o corpo de uma tabela, por exemplo. `styleOffset` o posiciona.
loader——