vue2实现
<template>
<div
class="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.scroll
this.container = this.$refs.container
this.list = this.$refs.list
this.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-23
this.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>
<div
class="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-23
end.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>