主题
虚拟列表
vue
<script setup>
import { ref, computed } from 'vue'
// 1. 模拟 10,000 条数据
const items = ref(Array.from({ length: 10000 }, (_, i) => `Item ${i}`))
// 2. 配置参数
const itemHeight = 50 // 每项高度
const visibleCount = 10 // 可见区域显示的最大条数
const containerHeight = itemHeight * visibleCount // 容器高度
// 3. 计算当前显示的范围
const scrollTop = ref(0)
const startIndex = computed(() => Math.floor(scrollTop.value / itemHeight))
const endIndex = computed(() => Math.min(startIndex.value + visibleCount, items.value.length))
const visibleItems = computed(() => items.value.slice(startIndex.value, endIndex.value))
const offsetY = computed(() => startIndex.value * itemHeight)
// 4. 监听滚动
const onScroll = (e) => {
scrollTop.value = e.target.scrollTop
}
</script>
<template>
<div class="virtual-list" @scroll="onScroll">
<!-- 5. 用一个占位容器撑起总高度 -->
<div class="list-container" :style="{ height: `${items.length * itemHeight}px` }">
<!-- 6. 只渲染可视区域的元素,并用 transformY 定位 -->
<div class="list-content" :style="{ transform: `translateY(${offsetY}px)` }">
<div v-for="(item, index) in visibleItems" :key="startIndex + index" class="list-item">
{{ item }}
</div>
</div>
</div>
</div>
</template>
<style scoped>
.virtual-list {
width: 300px;
height: v-bind(containerHeight + 'px');
/* 设置固定高度 */
overflow-y: auto;
border: 1px solid #ddd;
position: relative;
}
.list-container {
position: relative;
}
.list-content {
position: absolute;
top: 0;
left: 0;
right: 0;
}
.list-item {
height: 50px;
line-height: 50px;
border-bottom: 1px solid #eee;
padding-left: 10px;
background: white;
}
</style>