VirtualList.vue
<template>
<div ref="boxEle" class="virtual-list-box">
<div ref="scrollEle" class="virtual-list-scroll">
<div v-for="(v, i) in curData" :key="i" class="virtual-list-box-item">
<slot :item="v"></slot>
</div>
</div>
</div>
</template>
<script setup>
import { onMounted, ref, toRefs, watch } from "vue";
const props = defineProps({
data: {
type: Array,
default: () => [],
},
itemH: {
type: Number,
default: () => 0,
},
});
const { data, itemH } = toRefs(props);
const boxEle = ref(null);
const scrollEle = ref(null);
let maxVisibleNum = 0;
let curItemNum = 0;
const curData = ref([]);
let isScrollBusy = false;
onMounted(() => {
start();
});
function start() {
if (data.value.length === 0) {
curData.value = [];
return;
}
maxVisibleNum = Math.floor(boxEle.value.clientHeight / itemH.value);
curItemNum = maxVisibleNum * 2;
let initNum = data.value.length;
if (maxVisibleNum * 2 <= initNum) {
initNum = maxVisibleNum * 2;
boxEle.value.addEventListener("scroll", scrollHandler());
}
if (curData.value.length === data.value.length) {
boxEle.value.removeEventListener("scroll", scrollHandler());
}
curData.value = data.value.slice(0, initNum);
}
function scrollHandler() {
return () => {
if (isScrollBusy) return;
isScrollBusy = true;
window.requestAnimationFrame(() => {
isScrollBusy = false;
const scrollLine =
scrollEle.value.clientHeight -
boxEle.value.clientHeight -
Math.floor(itemH.value / 3);
const offsetTop = boxEle.value.scrollTop;
console.log(newVal);
if (offsetTop >= scrollLine) {
if (data.value.length > curItemNum + maxVisibleNum) {
curItemNum += maxVisibleNum;
} else {
curItemNum = data.length;
}
curData.value = data.value.slice(0, curItemNum);
}
});
};
}
watch(data, (newVal) => {
data.value = newVal;
start();
});
</script>
<style lang="less" scoped>
.virtual-list-box {
width: 100%;
height: 800px;
overflow: auto;
}
.virtual-list-box-item {
margin: 0px 10px 20px 10px;
}
</style>
使用
<VirtualList :itemH="200" :data="messageList">
<template v-slot="{ item }">
<messge-item :message-info="item" class="messgelist" :key="item.id as string" @submit-success="submitSuccess"
@handleUpMessage="handleUpMessage" />
</template>
</VirtualList>```