Skip to content
API 风格:

VirtualList 가상 목록 ​

화면에 보이는 창 내부의 항목만 렌더링하며, 고정 높이와 동적 높이 두 가지 모드를 지원합니다 (동적 모드는 사전 계산된 오프셋과 이진 탐색으로 위치를 찾습니다).

고정 높이 ​

고정 높이
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오버스캔 항목 수numberLH_VIRTUAL_OVERSCAN
sxsx 빠른 레이아웃 속성LhSxProps—

슬롯: default (스코프 { item, index }).

접근성 ​

  • 컨테이너는 overflow: auto로 키보드 스크롤이 가능합니다. 창 밖의 항목은 DOM에 존재하지 않으며, 스크린 리더는 필요에 따라 가져옵니다 (긴 목록에서는 본질적인 트레이드오프이므로, 검색/필터로 범위를 좁히는 것을 권장합니다)
  • 완전한 시맨틱 표가 필요하다면 Table을 사용하세요 (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

국풍의 아름다움으로 코드의 토대를 세웁니다