InfiniteLoader
Оборачивает VirtualList и вызывает onLoadMore, когда пользователь прокручивает в пределах threshold пикселей от низа (или верха, либо обоих).
Пропы
items
T[]
Текущий массив данных.
onLoadMore
() => Promise<void>
Вызывается, когда нужны дополнительные данные.
isLoading
boolean
Выполняется ли загрузка в данный момент.
hasMore
boolean
Доступны ли ещё данные.
threshold
number · по умолчанию: 200
Расстояние от края (px), при котором срабатывает onLoadMore.
direction
'down' | 'up' | 'both' · по умолчанию: 'down'
Какой(-ие) край(-я) запускают загрузку.
estimatedItemSize
number · по умолчанию: 50
Оценочная высота строки.
overscan
number · по умолчанию: 3
Дополнительные строки, рендерящиеся вне вьюпорта.
keyField
string · по умолчанию: 'id'
Поле ключа строки.
motionBlur
boolean · по умолчанию: false
Применить CSS-размытие, масштабируемое по скорости прокрутки при быстрой прокрутке.
Слоты
default
Область видимости: { item: T, index: number, style }
Содержимое строки.
loading-indicator
Область видимости: нет
Кастомный индикатор загрузки (показывается сверху/снизу в зависимости от direction).
empty
Область видимости: нет
Пустое состояние.
Emits
scroll
Payload: Event
visible-range-change
Payload: { start: number; end: number }
Публичный API
scrollTo(index, align?, options?)
Прокрутить к элементу. align — 'start' | 'center' | 'end' | 'auto'.
scrollToOffset(px, options?)
Прокрутить к пиксельному смещению.
getScrollElement()
Возвращает элемент, который реально прокручивается — сочетайте с VirtualScrollbar.
loaderRef.value?.scrollTo(index, align)
loaderRef.value?.scrollTo(index, 'start', { behavior: 'smooth' })
loaderRef.value?.scrollToOffset(px)
loaderRef.value?.getScrollElement()Пример
<script setup lang="ts">
import { ref } from 'vue'
import { InfiniteLoader } from 'vue-virtual-scroller-kit'
interface Post {
id: number
title: string
}
const posts = ref<Post[]>([])
const isLoading = ref(false)
const hasMore = ref(true)
let page = 0
async function loadMore() {
if (isLoading.value || !hasMore.value) return
isLoading.value = true
try {
const res = await fetch(`/api/posts?page=${page}`)
const data: Post[] = await res.json()
posts.value = [...posts.value, ...data]
hasMore.value = data.length === 20
page++
} finally {
isLoading.value = false
}
}
await loadMore()
</script>
<template>
<InfiniteLoader
:items="posts"
:on-load-more="loadMore"
:is-loading="isLoading"
:has-more="hasMore"
:estimated-item-size="72"
style="height: 600px"
>
<template #default="{ item }">
<div class="post-row">{{ item.title }}</div>
</template>
<template #loading-indicator>
<div style="padding: 16px; text-align: center">Loading…</div>
</template>
</InfiniteLoader>
</template>