VirtualList 仮想リスト
表示ウィンドウ内の項目のみをレンダリングします。固定高さと動的高さの 2 つのモードをサポートしています(動的モードは事前計算したオフセット + 二分探索で位置を特定します)。
固定高さ
固定高さ
0 番目 · 項目 1
1 番目 · 項目 2
2 番目 · 項目 3
3 番目 · 項目 4
vue
<script setup lang="ts">
const listData = Array.from({ length: 1000 }, (_, i) => `項目 ${i + 1}`)
</script>
<template>
<LhVirtualList :data="listData" :height="200" :item-height="40">
<template #default="{ item, index }">
<div>{{ index }} 番目 · {{ item }}</div>
</template>
</LhVirtualList>
</template>vue
<script>
export default {
data() {
return {
listData: Array.from({ length: 1000 }, (_, i) => `項目 ${i + 1}`),
}
},
}
</script>
<template>
<LhVirtualList :data="listData" :height="200" :item-height="40">
<template #default="{ item, index }">
<div>{{ index }} 番目 · {{ item }}</div>
</template>
</LhVirtualList>
</template>動的高さ
itemSize が各項目の高さを返します(測定結果に基づいて動的に返すことも可能です)。
動的高さ
項目 1
項目 2
項目 3
vue
<script setup>
const dynamicSize = (index) => (index % 3 === 0 ? 56 : 36)
</script>
<template>
<LhVirtualList :data="listData" :height="200" :item-size="dynamicSize">
<template #default="{ item, index }">{{ item }}</template>
</LhVirtualList>
</template>vue
<script>
export default {
data() {
return {
listData: Array.from({ length: 1000 }, (_, i) => `項目 ${i + 1}`),
}
},
methods: {
dynamicSize(index) {
return index % 3 === 0 ? 56 : 36
},
},
}
</script>
<template>
<LhVirtualList :data="listData" :height="200" :item-size="dynamicSize">
<template #default="{ item, index }">{{ item }}</template>
</LhVirtualList>
</template>事前レンダリングのバッファ
overscan は表示ウィンドウの外側に上下それぞれ何行分を事前レンダリングするかを指定し、高速スクロール時の白い隙間を減らします。
overscan
0 番目 · 項目 1
1 番目 · 項目 2
2 番目 · 項目 3
3 番目 · 項目 4
4 番目 · 項目 5
5 番目 · 項目 6
6 番目 · 項目 7
7 番目 · 項目 8
8 番目 · 項目 9
9 番目 · 項目 10
10 番目 · 項目 11
11 番目 · 項目 12
12 番目 · 項目 13
13 番目 · 項目 14
14 番目 · 項目 15
15 番目 · 項目 16
vue
<script setup lang="ts">
const listData = Array.from({ length: 1000 }, (_, i) => `項目 ${i + 1}`)
</script>
<template>
<LhVirtualList
:data="listData"
:item-height="40"
:height="200"
:overscan="8"
/>
</template>vue
<script>
export default {
data() {
return {
listData: Array.from({ length: 1000 }, (_, i) => `項目 ${i + 1}`),
}
},
}
</script>
<template>
<LhVirtualList
:data="listData"
:item-height="40"
:height="200"
:overscan="8"
/>
</template>API
LhVirtualList Props
| プロパティ | 説明 | 型 | デフォルト値 |
|---|---|---|---|
| data | データソース(項目のレンダリングは default スロットが担う) | any[] | — |
| height | コンテナの高さ(数値は px) | string | number | — |
| itemHeight | 固定高さモードの項目の高さ | number | — |
| itemSize | 動的高さモード:呼び出し側が各項目の高さを返す | (index: number) => number | — |
| overscan | オーバースキャンする項目数 | number | LH_VIRTUAL_OVERSCAN |
| sx | sx クイックレイアウトプロパティ | LhSxProps | — |
スロット:default(スコープ { item, index })。
アクセシビリティ
- コンテナは
overflow: autoでキーボードスクロール可能です。ウィンドウ外の項目は DOM に存在しないため、スクリーンリーダーは必要に応じて取得します(長いリストにおける固有のトレードオフです。検索/フィルタと組み合わせて範囲を絞ることをお勧めします) - 完全なセマンティックなテーブルが必要な場合は Table を使用してください(その仮想スクロールも同様に core 層の純関数で駆動されています)
型定義
本コンポーネントが外部にエクスポートする TypeScript の型構造は以下の通りです(packages/components/virtual-list/src/types.ts と @lh-ui/share/core/* のソースから自動抽出。各エントリーをクリックすると完全な定義を表示します。プロパティの説明は上記の Props 表を参照してください):
LhVirtualListProps
ts
export interface LhVirtualListProps {
/** データソース(項目のレンダリングは default スロットが担う) */
data: any[]
/** コンテナの高さ(数値は px) */
height: number | string
/** 固定高さモードの項目の高さ(itemSize との二択。itemSize を指定すると動的高さになる) */
itemHeight?: number
/** 動的高さモード:呼び出し側が各項目の高さを返す */
itemSize?: (index: number) => number
/** オーバースキャンする項目数 */
overscan?: number
/** sx クイックレイアウトプロパティ */
sx?: LhSxProps
}定数
本コンポーネントが使用する公開定数は以下の通りです(Props 表の「型 / デフォルト値」列で同名のエントリーをクリックするとここへジャンプします):
LH_VIRTUAL_ITEM_SIZE (@lh-ui/share/core/virtual-list より)
ts
/** デフォルトの推定項目高 */
export const LH_VIRTUAL_ITEM_SIZE = 40