实现原理:
测试多条数据是随机的,后续可以自行从父组件传入子元素的高度和数组;源码如下:
<template>
<!-- 可视区域的容器 -->
<div ref="list" class="list-container" @scroll="scrollEvent($event)">
<!-- 容器内的占位,高度为总列表高度,用于形成滚动条 -->
<div class="scroll-area" :style="{ height: listHeight + 'px' }"></div>
<!-- 为列表项的渲染区域 -->
<div class="view-area" :style="{ transform: getTransform }">
<div ref="items"
class="list-item"
v-for="item in visibleData"
:key="item.key"
:style="{ height: itemHeight + 'px',lineHeight: itemHeight + 'px' }"
>{
{ item.value }}</div>
</div>
</div>
</template>
<script>
export default {
data(){
return{
itemHeight:200,
listData:[],
screenHeight:0,//可视区域高度
startOffset:0,//偏移量
start:0,//起始索引
end:null,//结束索引
}
},
beforeMount(){
this.listData = new Array(100);
// 生成随机整数并赋值给数组的每个元素
for (let i = 0; i < this.listData.length; i++) {
this.listData[i] = {value:Math.floor(Math.random() * 100),key:i};
}
},
computed:{
listHeight(){//列表总高度
return this.listData.length * this.itemHeight;
},
visibleCount(){//可显示列表数据量
return Math.ceil(this.screenHeight / this.itemHeight)
},
getTransform(){ //偏移量style
return `translate3d(0,${this.startOffset}px,0)`;
},
visibleData(){//可视列表数据
return this.listData.slice(this.start, Math.min(this.end,this.listData.length));
}
},
mounted() {
this.screenHeight = this.$el.clientHeight;
this.start = 0;
this.end = this.start + this.visibleCount;
},
methods: {
scrollEvent() {
let scrollTop = this.$refs.list.scrollTop;//当前滚动所在位置
this.start = Math.floor(scrollTop / this.itemHeight);//当前开始索引
this.end = this.start + this.visibleCount;//当前结束索引
this.startOffset = scrollTop - (scrollTop % this.itemHeight);//此时的偏移量
}
}
}
</script>
<style scoped>
.list-container {
height: 100%;
overflow: auto;
position: relative;
}
.scroll-area {
position: absolute;
left: 0;
top: 0;
right: 0;
}
.view-area {
left: 0;
right: 0;
top: 0;
position: absolute;
text-align: center;
}
.list-item {
padding: 10px;
color: red
}
</style>