Pulled ALL skills from 15 source repositories: - anthropics/skills: 16 (docs, design, MCP, testing) - obra/superpowers: 14 (TDD, debugging, agents, planning) - coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth) - better-auth/skills: 5 (auth patterns) - vercel-labs/agent-skills: 5 (React, design, Vercel) - antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo) - Plus 13 individual skills from various repos Mosaic Stack is not limited to coding — the Orchestrator and subagents serve coding, business, design, marketing, writing, logistics, analysis, and more. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
185 lines
5.0 KiB
Markdown
185 lines
5.0 KiB
Markdown
---
|
|
category: Component
|
|
---
|
|
|
|
# useVirtualList
|
|
|
|
::: warning
|
|
Consider using [`vue-virtual-scroller`](https://github.com/Akryum/vue-virtual-scroller) instead, if you are looking for more features.
|
|
:::
|
|
|
|
Create virtual lists with ease. Virtual lists (sometimes called [_virtual scrollers_](https://vue-virtual-scroller-demo.netlify.app/)) allow you to render a large number of items performantly. They only render the minimum number of DOM nodes necessary to show the items within the `container` element by using the `wrapper` element to emulate the container element's full height.
|
|
|
|
## Usage
|
|
|
|
### Simple list
|
|
|
|
```ts
|
|
import { useVirtualList } from '@vueuse/core'
|
|
|
|
const { list, containerProps, wrapperProps } = useVirtualList(
|
|
Array.from(Array.from({ length: 99999 }).keys()),
|
|
{
|
|
// Keep `itemHeight` in sync with the item's row.
|
|
itemHeight: 22,
|
|
},
|
|
)
|
|
```
|
|
|
|
### Config
|
|
|
|
| State | Type | Description |
|
|
| ---------- | -------- | ----------------------------------------------------------------------------------------------- |
|
|
| itemHeight | `number` | ensure that the total height of the `wrapper` element is calculated correctly.\* |
|
|
| itemWidth | `number` | ensure that the total width of the `wrapper` element is calculated correctly.\* |
|
|
| overscan | `number` | number of pre-rendered DOM nodes. Prevents whitespace between items if you scroll very quickly. |
|
|
|
|
\* The `itemHeight` or `itemWidth` must be kept in sync with the height of each row rendered. If you are seeing extra whitespace or jitter when scrolling to the bottom of the list, ensure the `itemHeight` or `itemWidth` is the same height as the row.
|
|
|
|
### Reactive list
|
|
|
|
```ts
|
|
import { useToggle, useVirtualList } from '@vueuse/core'
|
|
import { computed } from 'vue'
|
|
|
|
const [isEven, toggle] = useToggle()
|
|
const allItems = Array.from(Array.from({ length: 99999 }).keys())
|
|
const filteredList = computed(() => allItems.filter(i => isEven.value ? i % 2 === 0 : i % 2 === 1))
|
|
|
|
const { list, containerProps, wrapperProps } = useVirtualList(
|
|
filteredList,
|
|
{
|
|
itemHeight: 22,
|
|
},
|
|
)
|
|
```
|
|
|
|
```vue
|
|
<template>
|
|
<p>Showing {{ isEven ? 'even' : 'odd' }} items</p>
|
|
<button @click="toggle">
|
|
Toggle Even/Odd
|
|
</button>
|
|
<div v-bind="containerProps" style="height: 300px">
|
|
<div v-bind="wrapperProps">
|
|
<div v-for="item in list" :key="item.index" style="height: 22px">
|
|
Row: {{ item.data }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
```
|
|
|
|
### Horizontal list
|
|
|
|
```ts
|
|
import { useVirtualList } from '@vueuse/core'
|
|
|
|
const allItems = Array.from(Array.from({ length: 99999 }).keys())
|
|
|
|
const { list, containerProps, wrapperProps } = useVirtualList(
|
|
allItems,
|
|
{
|
|
itemWidth: 200,
|
|
},
|
|
)
|
|
```
|
|
|
|
```vue
|
|
<template>
|
|
<div v-bind="containerProps" style="height: 300px">
|
|
<div v-bind="wrapperProps">
|
|
<div v-for="item in list" :key="item.index" style="width: 200px">
|
|
Row: {{ item.data }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
```
|
|
|
|
## Component Usage
|
|
|
|
```vue
|
|
<template>
|
|
<UseVirtualList :list="list" :options="options" height="300px">
|
|
<template #default="props">
|
|
<!-- you can get current item of list here -->
|
|
<div style="height: 22px">
|
|
Row {{ props.index }} {{ props.data }}
|
|
</div>
|
|
</template>
|
|
</UseVirtualList>
|
|
</template>
|
|
```
|
|
|
|
To scroll to a specific element, the component exposes `scrollTo(index: number) => void`.
|
|
|
|
## Type Declarations
|
|
|
|
```ts
|
|
type UseVirtualListItemSize = number | ((index: number) => number)
|
|
export interface UseHorizontalVirtualListOptions
|
|
extends UseVirtualListOptionsBase {
|
|
/**
|
|
* item width, accept a pixel value or a function that returns the width
|
|
*
|
|
* @default 0
|
|
*/
|
|
itemWidth: UseVirtualListItemSize
|
|
}
|
|
export interface UseVerticalVirtualListOptions
|
|
extends UseVirtualListOptionsBase {
|
|
/**
|
|
* item height, accept a pixel value or a function that returns the height
|
|
*
|
|
* @default 0
|
|
*/
|
|
itemHeight: UseVirtualListItemSize
|
|
}
|
|
export interface UseVirtualListOptionsBase {
|
|
/**
|
|
* the extra buffer items outside of the view area
|
|
*
|
|
* @default 5
|
|
*/
|
|
overscan?: number
|
|
}
|
|
export type UseVirtualListOptions =
|
|
| UseHorizontalVirtualListOptions
|
|
| UseVerticalVirtualListOptions
|
|
export interface UseVirtualListItem<T> {
|
|
data: T
|
|
index: number
|
|
}
|
|
export interface UseVirtualListReturn<T> {
|
|
list: Ref<UseVirtualListItem<T>[]>
|
|
scrollTo: (index: number) => void
|
|
containerProps: {
|
|
ref: Ref<HTMLElement | null>
|
|
onScroll: () => void
|
|
style: StyleValue
|
|
}
|
|
wrapperProps: ComputedRef<{
|
|
style:
|
|
| {
|
|
width: string
|
|
height: string
|
|
marginTop: string
|
|
}
|
|
| {
|
|
width: string
|
|
height: string
|
|
marginLeft: string
|
|
display: string
|
|
}
|
|
}>
|
|
}
|
|
/**
|
|
* Please consider using [`vue-virtual-scroller`](https://github.com/Akryum/vue-virtual-scroller) if you are looking for more features.
|
|
*/
|
|
export declare function useVirtualList<T = any>(
|
|
list: MaybeRef<readonly T[]>,
|
|
options: UseVirtualListOptions,
|
|
): UseVirtualListReturn<T>
|
|
```
|