一个简单的demo
<template>
<div class="box" ref="box" :style="{height:contentHeight+'px'}" @scroll="scrollListener">
<div class="content" :style="{position:'relative',height:showBoxHeight+'px'}">
<div class="position" :style="{position:'absolute',top:top+'px'}">
<div class="list" v-for="(item,index) in showList" :key="index" :style="{
height:itemHeight+'px',
lineHeight:itemHeight+'px'}">
{{ item }}
</div>
</div>
</div>
</div>
</template>
<script setup>
import { computed, onMounted, ref } from 'vue';
onMounted(()=>{
getList()
scrollListener()
})
const scrollTop=ref(0)//获取距离顶部距离
const showNum=ref(0) // 可展示个数
const box=ref(null) //大盒子节点
const top=ref(0) //距离顶部距离
const endIndex=ref(null) //结束位置
const startIndex=ref(0) //第一个节点位置
const contentHeight=600 //内容高度
const itemHeight=30 //每个节点高度
//构造虚拟列表
const list=ref([])
const showList=ref([])
const getList=()=>{
list.value= Array.from({length:100000}).map((item,index)=>{
return `第${index+1}条数据`
})
}
const showBoxHeight=computed(()=>{
return itemHeight*100000
})
const scrollListener=()=>{
//获取距离顶部位置
scrollTop.value=box.value.scrollTop
console.log(scrollTop.value,'距离顶部距离');
//展示数据个数
showNum.value=Math.ceil(contentHeight/itemHeight)
console.log(scrollTop.value,'展示数据个数');
//起点位置
startIndex.value=Math.floor(scrollTop.value/itemHeight)
console.log(scrollTop.value,'起点位置');
endIndex.value=startIndex.value+showNum.value
console.log(endIndex.value,'起点位置');
showList.value=list.value.slice(startIndex.value, endIndex.value)
console.log(showList.value,'起点位置');
top.value=startIndex.value*itemHeight
console.log(scrollTop.value,'起点位置');
}
</script>
<style lang="scss" scoped>
.box{
width: 500px;
// height: 600px;
box-shadow: 2px 2px 2px rgb(114, 113, 113);
overflow-y: auto;
}
</style>