长列表局部渲染(监听window滚动),wndonw滚动同理
场景
后端一股脑给了几千个数据,我们滚动过程永远只渲染20条
原理
滚动到底时候获取裁剪位置,的到需要渲染的20条数据,通过vue diff算法更新到dom
代码
<template>
<div class="container" @scroll="handleScroll">
<div v-if="showRefreshHint" class="refresh-hint">下拉刷新...</div>
<ul>
<li v-for="(item, index) in visibleItems" :key="index" class="item">
{{ item }}
</li>
</ul>
<div v-if="loadingMore" class="loading">加载中...</div>
</div>
</template>
<script>
export default {
data() {
return {
longArray: Array.from({ length: 1000 }, (_, i) => `Item ${i + 1}`), // 长数组
visibleCount: 20, // 当前可见的条目数
loadingMore: false, // 是否正在加载更多
showRefreshHint: false, // 是否显示刷新提示
lastScrollTop: 0, // 上一次的滚动位置
};
},
computed: {
visibleItems() {
return this.longArray.slice(0, this.visibleCount);
},
},
methods: {
handleScroll(event) {
const container = event.target;
const { scrollTop, scrollHeight, clientHeight } = container;
// 判断是否滚动到底部
if (scrollTop + clientHeight >= scrollHeight - 10) {
this.loadMore();
}
// 判断是否滚动到顶部
if (scrollTop <= 0) {
this.showRefreshHint = true;
this.refreshData();
} else {
this.showRefreshHint = false;
}
// 保存当前滚动位置
this.lastScrollTop = scrollTop;
},
loadMore() {
if (this.loadingMore) return; // 防止重复加载
// this.loadingMore = true;
// 模拟异步加载
// setTimeout(() => {
this.visibleCount += 20; // 每次加载更多条目
this.loadingMore = false;
//}, 1000);
},
refreshData() {
// 模拟刷新数据
// setTimeout(() => {
this.visibleCount = 20; // 重置可见条目数
this.showRefreshHint = false; // 隐藏刷新提示
// }, 1000);
},
},
};
</script>
<style>
.container {
height: 100vh;
overflow-y: auto;
position: relative;
background:#f3f2f2;
}
ul{
padding:0;
}
.refresh-hint {
text-align: center;
padding: 10px;
background-color: #f0f0f0;
position: sticky;
top: 0;
z-index: 10;
}
.loading {
text-align: center;
padding: 10px;
background-color: #f0f0f0;
}
.item {
height: 60px;
display: flex;
align-items: center;
padding: 0 10px;
background:#fff;
}
.item +.item{
margin-top:10px;
}
</style>
在线地址:
Vue SFC Playground