<template>
<div class="virtual-list" ref="container" @scroll="handleScroll">
<!-- 占位元素,用于撑开滚动区域 -->
<div class="list-phantom" :style="{ height: totalHeight + 'px' }"></div>
<!-- 实际渲染的列表内容 -->
<div class="list-content" :style="{ transform: `translateY(${offset}px)` }">
<div
v-for="item in visibleData"
:key="item.id"
class="list-item"
:style="{ height: itemHeight + 'px' }"
>
{{ item.content }}
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
data: [], // 所有数据
visibleData: [], // 当前可见的数据
itemHeight: 50, // 每项高度
screenHeight: 0, // 可视区域高度
startIndex: 0, // 可见区域的起始索引
endIndex: 0, // 可见区域的结束索引
offset: 0 // 列表的偏移量
};
},
computed: {
// 列表总高度
totalHeight() {
return this.data.length * this.itemHeight;
}
},
mounted() {
this.screenHeight = this.$refs.container.offsetHeight; // 获取可视区域高度
this.loadData(); // 初始加载数据
this.updateVisibleData(); // 初始渲染可见数据
},
methods: {
// 模拟分段加载数据
loadData() {
// 假设每次加载 100 条数据
setTimeout(() => {
const newData = Array.from({ length: 100 }, (_, i) => ({
id: this.data.length + i + 1,
content: `Item ${this.data.length + i + 1}`
}));
this.data = this.data.concat(newData);
console.log(this.data);
this.updateVisibleData(); // 初始渲染可见数据
}, 100);
},
// 更新可见区域的数据
updateVisibleData() {
const startIndex = Math.floor(this.offset / this.itemHeight); // 起始索引
const endIndex = Math.min(
startIndex + Math.ceil(this.screenHeight / this.itemHeight),
this.data.length
); // 结束索引
this.startIndex = startIndex;
this.endIndex = endIndex;
this.visibleData = this.data.slice(startIndex, endIndex);
},
// 处理滚动事件
handleScroll() {
const scrollTop = this.$refs.container.scrollTop; // 获取滚动距离
console.log(this.$el);
this.offset = scrollTop; // 更新偏移量
this.updateVisibleData(); // 更新可见数据
// 如果滚动到底部,加载更多数据
if (scrollTop + this.screenHeight >= this.totalHeight) {
console.log(1);
this.loadData();
}
}
}
};
</script>
<style>
.virtual-list {
height: 100vh; /* 可视区域高度 */
overflow-y: auto; /* 允许垂直滚动 */
position: relative;
}
.list-phantom {
position: absolute;
left: 0;
top: 0;
right: 0;
z-index: -1;
}
.list-content {
position: absolute;
left: 0;
top: 0;
right: 0;
}
.list-item {
display: flex;
align-items: center;
padding: 10px;
box-sizing: border-box;
border-bottom: 1px solid #eee;
}
</style>
vue2 长列表+虚拟dom
最新推荐文章于 2026-03-30 02:44:34 发布

1万+

被折叠的 条评论
为什么被折叠?



