<List :arr="dataList">
<template #default="{item}">
{{item * 3}}
</template>
</List>
<template>
<div class=''>
<div class="view_port" ref="viewPortRef" @scroll="changeScroll">
<div class="scroll_bar" ref="scrollBarRef"></div>
<div class="list" :style="{ transform: `translate(0, ${offsetTop}px)` }">
<div :style="{ 'height': size + 'px' }" v-for="(item, index) in itemsList" :key="index">
<slot :item="item">{{item}}</slot>
</div>
</div>
</div>
</div>
</template>
<script setup lang='ts'>
import { withDefaults, defineProps, ref, onMounted, computed } from "vue";
const props = withDefaults(defineProps<{
arr: Array<number>, // 需要滚动的数据
remain?: number, // 每个元素的高度
size?: number // 视口展示元素的数量
}>(), {
remain: 20,
size: 20
})
const viewPortRef = ref<HTMLElement>();
const scrollBarRef = ref<HTMLElement>();
const initPage = () => {
// 设置视口的高度
viewPortRef.value!.style.height = props.remain * props.size + "px";
// 设置整个滚动条的高度
scrollBarRef.value!.style.height = props.arr.length * props.size + 'px';
}
const startIndex = ref(0);
const endIndex = ref(props.size);
const offsetTop = ref(0);
// 用于获取真实得到的列表
const itemsList = computed(() => props.arr.slice(startIndex.value, endIndex.value))
// 监听页面的滚动
const changeScroll = () => {
// 计算向上卷入的元素的开始下标,乡下取整
startIndex.value = Math.floor(viewPortRef.value!.scrollTop / props.size);
// 计算截取的元素结束下标
endIndex.value = startIndex.value + props.size;
// 可视高度向下偏移的数量
offsetTop.value = startIndex.value * props.size
}
onMounted(() => {
initPage();
})
</script>
<style scoped>
.view_port {
overflow-y: scroll;
position: relative;
}
.list {
position: absolute;
top: 0;
left: 0;
}
</style>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了