1、直接看代码
<template><!--定义一个大容器,此容器可以滚动--><div class="view" ref="viewRef" @scroll="handleScroll"><!--定义一个可以撑满整个data的容器,主要是让父元素滚动起来--><div class="phantom" :style="{ height: `${itemSize * data.length}px` }"></div><!--显示元素列表 因为list也是绝对定位,当父元素进行滚动时,父元素需要平移来表示滚动(实际是看到的是没有滚动)--><div class="list" :style="{ transform: `translateY(${translateLen}px)` }"><!--显示每条数据--><div v-for="item in visibleList" :style="{ height: `${itemSize}px` }">{{ item }}</div></div></div>
</template><script setup>
import {computed, reactive, ref} from 'vue';//模拟请求回来的数据
const data = reactive((() => {const arr = [];for (let i = 0; i < 1000000; i++) arr[i] = i;return arr;
})());
// 每条数据占据的高度像素值
const itemSize = 40
// 移动的距离
const translateLen = ref(0);
// 绑定的元素
const viewRef = ref(null);
// 从那条数据开始取值
const start = ref(0);
// 可视区显示的条数
const visibleCount = computed(() => Math.ceil(viewRef.value?.clientHeight / itemSize));
// 可视区显示的数据内容(即需要渲染的所有数据内容)
const visibleList = computed(() => data.slice(start.value, start.value + visibleCount.value));
// 滚动起来后需要处理的显示的开始位置和要移动的距离
const handleScroll = () => {const scrollTop = viewRef.value.scrollTop;start.value = Math.floor(scrollTop / itemSize);console.log("scrollTop==>", scrollTop)translateLen.value = scrollTopconsole.log("translateLen.value==>", translateLen.value)
}</script><style scoped>
.view {position: relative;height: 400px;width: 400px;overflow: auto;
}.phantom {/* 必须要绝对定位 */position: absolute;width: 100%;background-color: pink;
}.list {/* 必须要绝对定位 */position: absolute;
}
</style>
显示的结果如下:
当向下滚动时:
再向上滚动: