VueUse 虚拟列表的使用

<script setup lang="ts">
import type { Ref } from 'vue'
import { computed, ref } from 'vue'
import { useVirtualList } from '@vueuse/core'

const index: Ref = ref()
const search = ref('')

const allItems = Array.from(Array(99999).keys())
.map(i => ({
height: i % 2 === 0 ? 42 : 84,
size: i % 2 === 0 ? 'small' : 'large',
}))

const filteredItems = computed(() => {
return allItems.filter(i => i.size.startsWith(search.value.toLowerCase()))
})

const { list, containerProps, wrapperProps, scrollTo } = useVirtualList(
filteredItems,
{
itemHeight: i => (filteredItems.value[i].height + 8),
overscan: 10,
},
)
function handleScrollTo() {
scrollTo(index.value)
}
</script>

<template>
<div>
<div>
<div class="inline-block mr-4">
Jump to index
<input v-model="index" placeholder="Index" type="number">
</div>
<button type="button" @click="handleScrollTo">
Go
</button>
</div>
<div>
<div class="inline-block mr-4">
Filter list by size
<input v-model="search" placeholder="e.g. small, medium, large" type="search">
</div>
</div>
<div v-bind="containerProps" class="h-300px overflow-auto p-2 bg-gray-500/5 rounded">
<div v-bind="wrapperProps">
<div
v-for="{ index, data } in list"
:key="index"
class="border border-$c-divider mb-2"
:style="{
height: `${data.height}px`,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}"
>
Row {{ index }} <span opacity="70" m="l-1">({{ data.size }})</span>
</div>
</div>
</div>
</div>
</template>