<script setup>
import { ref, onMounted } from "vue";
const windowRef = ref(null);
const itemHeight = 100;
const bufferNum = 5;
//源数据:10W条
const allData = ref(Array.from({ length: 100000 }, (_, i) => i));
const showingList = ref([]);
const showingNum = ref(0);
const top = ref(0);
onMounted(() => {
// 计算可视元素应该有几个dom
showingNum.value =
Math.ceil(
parseFloat(window.getComputedStyle(windowRef.value).getPropertyValue("height")) / itemHeight
) + 1;
// 从总数据中截取数据
showingList.value = allData.value.slice(0, showingNum.value);
windowRef.value.addEventListener("scroll", handleScroll);
});
function handleScroll(e) {
// 防止startIndex小于0
const startIndex = Math.max(Math.floor(e.target.scrollTop / itemHeight) - bufferNum, 0);
// 防止endIndex大于allData.value.length
const endIndex = Math.min(startIndex + showingNum.value + bufferNum * 2, allData.value.length);
// 更新可视元素
showingList.value = allData.value.slice(startIndex, endIndex);
// 计算top偏移量
top.value = startIndex * itemHeight;
}
</script>
<template>
<div class="window" ref="windowRef">
<div :style="{ height: itemHeight * allData.length + 'px' }" />
<div class="showingListWrapper" :style="{ top: top + 'px' }">
<div
class="listItem"
:style="{
height: itemHeight + 'px',
}"
v-for="num in showingList"
:key="num"
>
{{ num }}
</div>
</div>
</div>
</template>
<style scoped>
.window {
height: 550px;
width: 300px;
border: 1px solid red;
overflow: auto;
position: relative;
}
.showingListWrapper {
position: absolute;
left: 0;
}
.listItem {
width: 200px;
border: 2px solid #dde5ff;
box-sizing: border-box;
background-color: #1772f6;
color: #fff;
}
</style>
vue3实现虚拟列表
最新推荐文章于 2024-07-19 17:59:08 发布