dom
<template>
<div class="">
<el-card class="elCard" :style="{ height: elCardHeight }" @scroll.native="scroll">
<div class="virtual_box" ref="virtualBox" :style="{ height: virtualContextHeight }"></div>
<div class="real_content" ref="realContent" :style="{ transform: realContentTransformY }">
<ul>
<li v-for="item in contentList" :key="item.id">{{ item.title }}</li>
</ul>
</div>
</el-card>
</div>
</template>
script
<script>
export default {
name: "",
data() {
return {
itemNum: 0,
offsetTop: 0,
totalList: [],
contentList: [],
elCardHeight: 0,
virtualContextHeight: 0,
start: 0,
end: 0,
realContentTransformY: 'translate3d(0)',
itemHeight: 60
};
},
created() {
this.mockTotalList();
},
methods: {
mockTotalList() {
setTimeout(() => {
for (let i = 0; i < 50000; i++) {
this.totalList.push({
id: i,
title: `内容${i}`,
});
}
this.initData()
})
},
initData () {
const maxHeight = 600
this.itemNum = Math.ceil(maxHeight/this.itemHeight) + 1
this.elCardHeight = this.totalList.length * this.itemHeight >= maxHeight ? maxHeight + 'px' : this.totalList.length * this.itemHeight + 'px'
this.virtualContextHeight = this.totalList.length * this.itemHeight + 'px'
this.start = 0
this.end = this.totalList.length > (this.start + this.itemNum) ? (this.start + this.itemNum) : this.totalList.length
this.contentList = this.totalList.slice(this.start, this.end)
},
scroll (e) {
const scrollTop = e.target.scrollTop
const scrollHeight = e.target.scrollHeight
const clientHeight = e.target.clientHeight
if (scrollHeight - scrollTop !== clientHeight) {
const newStart = Math.floor(scrollTop / 60)
if (newStart !== this.start) {
this.start = newStart
this.end = this.totalList.length > (this.start + this.itemNum) ? (this.start + this.itemNum) : this.totalList.length
const offsetTop = scrollTop - (scrollTop % 60)
console.log('offsetTop', offsetTop)
this.realContentTransformY = `translate3d(0, ${offsetTop}px, 0`
this.contentList = [...this.totalList.slice(this.start, this.end)]
console.log(this.contentList)
return
}
}
}
},
};
</script>
css
<style lang='scss' scoped>
* {
padding: 0;
margin: 0;
}
.el-card {
padding: 0;
margin: 20px;
max-height: 600px;
position: relative;
overflow: auto;
::v-deep .el-card__body, .el-main {
padding: 0;
}
.virtual_box {
position: absolute;
left: 0;
right: 0;
height: 1000px;
z-index: -1;
}
.real_content {
position: absolute;
left: 0;
right: 0;
transform: translate3d(0);
li {
line-height: 80px;
border-bottom: 1px solid #eee;
box-sizing: border-box;
}
}
}
</style>