Appearance
组件
vue
<template>
<div
ref="container"
class="overflow-y-auto border"
:style="{ height: `${props.sliceSize * props.itemsSize}px` }"
@scroll="onScroll"
>
<div :style="{ height: `${totalHeight}px` }">
<div :style="{ transform: `translateY(${offsetY}px)` }">
<div
v-for="(item, index) in visibleItems"
:key="startIndex + index"
:style="{
height: `${props.itemsSize}px`,
lineHeight: `${props.itemsSize}px`
}"
class="border-b"
>
{{ item }}
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
const props = withDefaults(
defineProps<{
items: any[]
itemsSize: number
sliceSize?: number
}>(),
{
sliceSize: 10
}
)
const scrollTop = ref(0)
const container = ref(null)
const totalHeight = computed(() => props.items.length * props.itemsSize)
const startIndex = computed(() => Math.floor(scrollTop.value / props.itemsSize))
const endIndex = computed(() =>
Math.min(props.items.length - 1, startIndex.value + props.sliceSize + 2)
)
const offsetY = computed(() => startIndex.value * props.itemsSize)
const visibleItems = computed(() =>
props.items.slice(startIndex.value, endIndex.value + 1)
)
const onScroll = e => {
scrollTop.value = e.target.scrollTop
}
</script>使用
vue
<template>
<div>
<h2>虚拟列表示例(Vue)</h2>
<VirtualList :items="items" :items-size="40" />
</div>
</template>
<script setup>
import VirtualList from '@/components/VirtualList.vue'
const items = new Array(100).fill(null).map((_, i) => `Item ${i + 1}`)
// const items = Array.from({ length: 100 }, (_, i) => `Item ${i + 1}`)
</script>