Raccourci clavier : Ctrl + K
Commencer

Liste virtuelle

VVirtualList ne rend que les lignes proches de sa zone visible, pour des listes trop longues pour être rendues entières. Elle défile elle-même : donnez-lui une hauteur avec height, ou une hauteur bornée dans votre CSS.

Utilisation

vue
Invoice 10.00 €
Invoice 279.19 €
Invoice 3158.38 €
Invoice 4237.57 €
Invoice 5316.76 €
Invoice 6395.95 €
Invoice 7475.14 €
Invoice 8554.33 €
Invoice 9633.52 €
Invoice 10712.71 €
<script setup lang="ts">
import { VVirtualList } from 'vectis-ui'

const invoices = Array.from({ length: 10000 }, (_, i) => ({
  id: i + 1,
  amount: ((i * 7919) % 100000) / 100,
}))
</script>

<template>
  <VVirtualList :items="invoices" item-key="id" :height="320" label="Invoices" class="list">
    <template #default="{ item }">
      <div class="row">
        <span>Invoice {{ item.id }}</span>
        <span>{{ item.amount.toFixed(2) }} €</span>
      </div>
    </template>
  </VVirtualList>
</template>

<style scoped>
.list {
  max-inline-size: 420px;
  border: 1px solid var(--vectis-color-border);
}

.row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-block-size: 40px;
  padding-inline: var(--vectis-space-3);
  border-block-end: 1px solid var(--vectis-color-border);
}
</style>

Exemples

Lignes de hauteurs différentes

itemSize n’est que la hauteur supposée des lignes pas encore rendues. Chaque ligne est mesurée une fois et retenue sous son itemKey ; renseignez-le si des lignes peuvent être insérées, retirées ou réordonnées.

vue
Note 1

Paid in three instalments after a dispute about the delivery date, settled with a discount on the next order.

Note 2

Paid on delivery.

Note 3

Paid on delivery.

Note 4

Paid in three instalments after a dispute about the delivery date, settled with a discount on the next order.

Note 5

Paid on delivery.

Note 6

Paid on delivery.

Note 7

Paid in three instalments after a dispute about the delivery date, settled with a discount on the next order.

Note 8

Paid on delivery.

Note 9

Paid on delivery.

Note 10

Paid in three instalments after a dispute about the delivery date, settled with a discount on the next order.

<script setup lang="ts">
import { VVirtualList } from 'vectis-ui'

const notes = Array.from({ length: 2000 }, (_, i) => ({
  id: i + 1,
  text:
    i % 3 === 0
      ? 'Paid in three instalments after a dispute about the delivery date, settled with a discount on the next order.'
      : 'Paid on delivery.',
}))
</script>

<template>
  <VVirtualList
    :items="notes"
    item-key="id"
    :item-size="64"
    :height="320"
    label="Notes"
    class="list"
  >
    <template #default="{ item }">
      <article class="note">
        <strong>Note {{ item.id }}</strong>
        <p>{{ item.text }}</p>
      </article>
    </template>
  </VVirtualList>
</template>

<style scoped>
.list {
  max-inline-size: 360px;
  border: 1px solid var(--vectis-color-border);
}

.note {
  padding: var(--vectis-space-2) var(--vectis-space-3);
  border-block-end: 1px solid var(--vectis-color-border);
}

.note p {
  margin: var(--vectis-space-1) 0 0;
  color: var(--vectis-color-text-muted);
}
</style>

Défiler jusqu’à une ligne

La méthode scrollToIndex(index, align) rend la ligne si besoin et l’amène dans la zone visible : en haut (start), au centre (center), en bas (end), ou avec le plus petit déplacement par défaut.

vue
Invoice 1
Invoice 2
Invoice 3
Invoice 4
Invoice 5
Invoice 6
Invoice 7
Invoice 8
Invoice 9
Invoice 10
<script setup lang="ts">
import { ref } from 'vue'
import { VButton, VVirtualList, type VirtualListAlign } from 'vectis-ui'

const invoices = Array.from({ length: 10000 }, (_, i) => ({ id: i + 1 }))
const list = ref<{ scrollToIndex: (index: number, align?: VirtualListAlign) => void } | null>(null)
</script>

<template>
  <div class="stack">
    <div class="actions">
      <VButton @click="list?.scrollToIndex(4999, 'center')">Go to invoice 5,000</VButton>
      <VButton variant="outline" @click="list?.scrollToIndex(0, 'start')">Back to the top</VButton>
    </div>
    <VVirtualList
      ref="list"
      :items="invoices"
      item-key="id"
      :height="320"
      label="Invoices"
      class="list"
    >
      <template #default="{ item }">
        <div class="row">Invoice {{ item.id }}</div>
      </template>
    </VVirtualList>
  </div>
</template>

<style scoped>
.stack {
  display: grid;
  gap: var(--vectis-space-3);
  max-inline-size: 420px;
}

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--vectis-space-2);
}

.list {
  border: 1px solid var(--vectis-color-border);
}

.row {
  display: flex;
  align-items: center;
  min-block-size: 40px;
  padding-inline: var(--vectis-space-3);
  border-block-end: 1px solid var(--vectis-color-border);
}
</style>

Défilement infini

hasMore émet load-more quand la fin de la liste approche. Ajoutez les lignes suivantes à items ; pendant ce temps, loading termine la liste par une ligne de chargement.

vue
Event 1
Event 2
Event 3
Event 4
Event 5
Event 6
Event 7
Event 8
Event 9
Event 10
<script setup lang="ts">
import { computed, ref } from 'vue'
import { VVirtualList } from 'vectis-ui'

const total = 200

function page(from: number) {
  return Array.from({ length: 40 }, (_, i) => ({ id: from + i + 1 }))
}

const events = ref(page(0))
const loading = ref(false)
const hasMore = computed(() => events.value.length < total)

// Stands in for a request to your API.
function loadMore() {
  loading.value = true
  setTimeout(() => {
    events.value = [...events.value, ...page(events.value.length)]
    loading.value = false
  }, 600)
}
</script>

<template>
  <VVirtualList
    :items="events"
    item-key="id"
    :height="320"
    :loading="loading"
    :has-more="hasMore"
    label="Activity"
    class="list"
    @load-more="loadMore"
  >
    <template #default="{ item }">
      <div class="row">Event {{ item.id }}</div>
    </template>
  </VVirtualList>
</template>

<style scoped>
.list {
  max-inline-size: 420px;
  border: 1px solid var(--vectis-color-border);
}

.row {
  display: flex;
  align-items: center;
  min-block-size: 40px;
  padding-inline: var(--vectis-space-3);
  border-block-end: 1px solid var(--vectis-color-border);
}
</style>

Lignes focusables

La liste a le rôle list et reçoit le focus, le clavier la fait donc défiler. La ligne qui a le focus reste rendue quand la liste défile. Si chaque ligne contient un contrôle, tabindex="-1" retire l’arrêt de tabulation de la liste. La recherche dans la page n’atteint que les lignes rendues : proposez une recherche pour les longues listes.

vue
Invoice 1
Invoice 2
Invoice 3
Invoice 4
Invoice 5
Invoice 6
Invoice 7
Invoice 8
Invoice 9
Invoice 10
<script setup lang="ts">
import { VButton, VVirtualList } from 'vectis-ui'

const invoices = Array.from({ length: 10000 }, (_, i) => ({ id: i + 1 }))
</script>

<template>
  <VVirtualList
    :items="invoices"
    item-key="id"
    :height="320"
    label="Invoices"
    tabindex="-1"
    class="list"
  >
    <template #default="{ item }">
      <div class="row">
        <span>Invoice {{ item.id }}</span>
        <VButton size="sm" variant="ghost" :aria-label="`Open invoice ${item.id}`">Open</VButton>
      </div>
    </template>
  </VVirtualList>
</template>

<style scoped>
.list {
  max-inline-size: 420px;
  border: 1px solid var(--vectis-color-border);
}

.row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-block-size: 40px;
  padding-inline: var(--vectis-space-3);
  border-block-end: 1px solid var(--vectis-color-border);
}
</style>

API

Props

PropTypeDéfaut
itemsT[]aucune
virtual-list.api.VVirtualList.props.items
itemKeystringaucune
virtual-list.api.VVirtualList.props.itemKey
itemSizenumber40
virtual-list.api.VVirtualList.props.itemSize
overscannumber5
virtual-list.api.VVirtualList.props.overscan
initialCountnumber10
virtual-list.api.VVirtualList.props.initialCount
heightnumber | stringaucune
virtual-list.api.VVirtualList.props.height
labelstringaucune
virtual-list.api.VVirtualList.props.label
loadingbooleanfalse
virtual-list.api.VVirtualList.props.loading
loadingTextstringaucune
virtual-list.api.VVirtualList.props.loadingText
hasMorebooleanfalse
virtual-list.api.VVirtualList.props.hasMore

Événements

ÉvénementType
load-more[]
virtual-list.api.VVirtualList.events.loadMore

Slots

SlotType
defaultVirtualListItemSlotProps<T>
virtual-list.api.VVirtualList.slots.default
loading{}
virtual-list.api.VVirtualList.slots.loading

Types

Types utilisés dans les tables d’API. Importez les types exportés depuis vectis-ui.

export interface VirtualListItemSlotProps<T> {
  item: T
  index: number
}