众所周知,列表滚动加载这种需求很常见,特别是在移动webapp上。Github上各款移动端ui框架都会包含滚动加载功能的组件,但它们往往只提供很基础的功能,例如简单地监听滚动条并在满足条件的时候触发回调,然后通过某些方法把新的元素加入到页面末尾。这样的确可以解决分页加载数据的问题,但是在一个数据量比较大的情况下,页面元素会增加得很快,这时就会导致性能问题,想象一下,如果一个移动端页面上有1万条数据需要显示在页面的时候,是多么恐怖的事情。
<template>
<!--
确认每一条数据的高度,可以确认可视区域内可以显示多少条数据,
并且确认滚动时上去了几条,就要动态更新几条
-->
<div class="container" @scroll="handleSrcoll" ref="containerRef" :style="{ height: containerHeight }">
<!-- 显示数据的地方:数据列表 -->
<div class="list" :style="{ top: listTop }">
<!-- 可视区域 -->
<div v-for="item in showData" :key="item.id">
{{ item.content }}
</div>
</div>
<!-- 空白区域 -->
<div class="bar" :style="{ height: barHeight }"></div>
</div>
</template>
<script setup>
// 要进行渲染的列表数据
const list = reactive(new Array(10000).fill('').map((item,index)=>({
id:index+1,
content:`列表数据内容:${index+1}`
})))
// 每一条数据的高度
const size = ref(40)
// 每次渲染的数据条数
const showNumber = ref(10)
// 展示数据的起始下标
const start = ref(0)
// 展示数据的结束下标
const end = showNumber
// 最终显示的数据
const showData = computed(()=>list.slice(unref(start), unref(end)))
// 容器的高度
const containerHeight = unref(size)*unref(showNumber)+'px'
// 撑开高度,产生滚动
let barHeight = computed(()=>unref(size)*list.length+'px')
// 列表上移滚动的距离
const listTop = computed(()=>{
return unref(start)*unref(size)+'px'
})
// 容器的滚动事件
const containerRef = ref(null)
const handleSrcoll = ()=>{
const scrollTop = containerRef.value.scrollTop
console.log(scrollTop,'scrollTopscrollTop');
// 起始下标
start.value = Math.floor(scrollTop/size.value);
// 结束下标
end.value = start.value + 10
}
onUnmounted(() => {
window.removeEventListener('scroll', handleSrcoll)
})
</script>
<style scoped>
.container {
overflow: scroll;
background: rgba(150, 150, 150, .5);
font-size: 20px;
font-weight: bold;
line-height: 40px;
width: 500px;
margin: 0 auto;
position: relative;
text-align: center;
}
.list {
position: absolute;
top: 0;
width: 100%;
}
</style>
效果如下: