Render hàng nghìn DOM nodes cùng lúc rất chậm. Virtual scrolling chỉ render visible items:
Vue Virtual Scroller (@vueuse/components hoặc vue-virtual-scroller):
vue
<script setup>
import { useVirtualList } from '@vueuse/core'
const items = ref(Array.from({ length: 10000 }, (_, i) => ({ id: i, name: `Item ${i}` })))
const { list, containerProps, wrapperProps } = useVirtualList(items, {
itemHeight: 40, // Fixed height per item (required)
})
</script>
<template>
<!-- Container với overflow scroll -->
<div v-bind="containerProps" style="height: 600px; overflow-y: auto">
<!-- Wrapper với total height để scroll bar đúng -->
<div v-bind="wrapperProps">
<!-- Chỉ visible items được render -->
<div
v-for="{ data: item } in list"
:key="item.id"
style="height: 40px"
>
{{ item.name }}
</div>
</div>
</div>
</template>Với variable-height items, dùng vue-virtual-scroller's DynamicScroller.
Kết hợp với v-memo cho items có nhiều reactive dependencies.
Virtual scrolling renders only visible items, not the entire list.
Using @vueuse/core's useVirtualList:
vue
<script setup>
const items = ref(/* 10000 items */)
const { list, containerProps, wrapperProps } = useVirtualList(items, { itemHeight: 40 })
</script>
<template>
<div v-bind="containerProps" style="height: 600px; overflow-y: auto">
<div v-bind="wrapperProps">
<div v-for="{ data: item } in list" :key="item.id" style="height: 40px">
{{ item.name }}
</div>
</div>
</div>
</template>For variable-height items use vue-virtual-scroller's DynamicScroller.
Combine with v-memo for items with many reactive dependencies.