参考: vue 怎么实现虚拟滚动效果? - 知乎
vue2实现
<template><divclass="container"ref="container":style="{ '--rowHeight': rowHeight + 'px' }"@scroll="onScroll"><div class="scroll" ref="scroll"></div><div class="list" ref="list"><div class="list-item" v-for="item in renderList" :key="item">{{ item.index }}</div></div></div>
</template><script >export default {name: 'hhTest',data () {return {dataList: [],list: null,scroll: null,container: null,start: 0,end: 20,rowHeight: 20,rowCount: 20// jumpType: this.$store.getters.tempStr}},computed: {renderList () {return this.dataList.slice(this.start, this.end)}},mounted () {this.scroll = this.$refs.scrollthis.container = this.$refs.containerthis.list = this.$refs.listthis.container.style.height = this.rowHeight * this.rowCount + 'px'this.scroll.style.height = this.rowHeight * this.dataList.length + 'px'console.log(this.container.style.height, this.scroll.style.height)},created () {this.dataList = new Array(1000000).fill(null).map((item, idx) => {return { index: idx + 1 }})},methods: {onScroll () {const scrollTop = this.container.scrollTop// 使用 容器的scrollTop 属性可以计算出 滚出去了多少个子元素// 假设 scrollTop 的值为 600 , 子元素的高度为20 那说明 滚出去了3个子元素const count = Math.round(scrollTop / this.rowHeight)this.start = count // 从第3个开始截取数据源// 3-23this.end = this.start + this.rowCount// 需要将list向下平移 scrollTop 的距离,回到 container容器的可视区中, 实现虚拟滚动this.list.style.transform = `translateY(${scrollTop}px)`}}
}</script><style>
.container {/* width: 300px; */background-color: pink;position: absolute;left: 0;right: 0;bottom: 0;top: 0;margin: auto;overflow: auto;height: 500px;
}
.list {width: 100%;height: 100%;position: absolute;top: 0;background: bisque;
}.list-item {width: 100%;height: var(--rowHeight);transition: all 0.3;
}.scroll {
}
</style>
vue3代码
<template><divclass="container"ref="container":style="{ '--rowHeight': rowHeight + 'px' }"@scroll="onScroll"><div class="scroll" ref="scroll"></div><div class="list" ref="list"><div class="list-item" v-for="item in renderList" :key="item">{{ item.index }}</div></div></div>
</template><script setup>
import { computed, onMounted, ref } from "vue";let dataList = new Array(1000000).fill(null).map((item, idx) => {return { index: idx + 1 };
});let list = ref(null);
let container = ref(null);
let scroll = ref(null);let start = ref(0);
let end = ref(20);// 监听 容器滚动
const onScroll = () => {let scrollTop = container.value.scrollTop;// 使用 容器的scrollTop 属性可以计算出 滚出去了多少个子元素// 假设 scrollTop 的值为 600 , 子元素的高度为20 那说明 滚出去了3个子元素let count = Math.round(scrollTop / rowHeight.value);start.value = count; // 从第3个开始截取数据源// 3-23end.value = start.value + rowCount.value;// 需要将list向下平移 scrollTop 的距离,回到 container容器的可视区中, 实现虚拟滚动list.value.style.transform = `translateY(${scrollTop}px)`;
};// 假设是父组件传递进来的参数// 子元素高度
let rowHeight = ref(20);// 可视区内显示多少个子元素
let rowCount = ref(20);let renderList = computed(() => {return dataList.slice(start.value, end.value);
});// 初始化变量
onMounted(() => {container.value.style.height = rowHeight.value * rowCount.value + "px";scroll.value.style.height = rowHeight.value * dataList.length + "px";console.log(container.value.style.height, scroll.value.style.height);
});
</script><style>
.container {/* width: 300px; */background-color: pink;position: absolute;left: 0;right: 0;bottom: 0;top: 0;margin: auto;overflow: auto;
}
.list {width: 100%;height: 100%;position: absolute;top: 0;
}.list-item {width: 100%;height: var(--rowHeight);transition: all 0.3;
}.scroll {
}
</style>