1.新建子组件,将数据传递过去(几万条数据的数组,一次性展示多少条,每条数据的行高).
<template>
<div class="vitualScroll">
<sub-scroll :dataList="dataList" :rowCount="20" :rowHeight="20"></sub-scroll>
</div>
</template>
<script>
import subScroll from "./components/subScroll.vue"
export default{
name: 'virtualScroll',
data(){
return {
//冻结数组,初步优化
dataList: Object.freeze(new Array(20000).fill(null).map((item, index) => ({ n: index+1 })))
}
},
components:{
subScroll
}
}
</script>
<style scoped lang="less">
.vitualScroll{
width: 100%;
height: 100%;
}
</style>
2.子组件subScroll.vue
div.scrollBar用来使父盒子出现滚动条,div.scrollBar的高度就是数据总条数*单条数据的高度。
div.list才是v-for数据的盒子,采用绝对定位,在父元素滑动事件中更新数据,并且将div.list的位置拉回来(div.list采用绝对定位,滑动滚动会往上跑)
<template>
<div class="scrollView" ref="scrollView" :style="{'--rowHeight': $props.rowHeight + 'px'}" @scroll="onScroll()">
<div class="scrollBar" :style="{'--scrollBarHeight': $props.dataList.length * $props.rowHeight + 'px'}">
</div>
<div class="list" ref="list">
<div class="item" v-for="(item, index) in copyDataList" :key="index">
{{ item.n }}
</div>
</div>
</div>
</template>
<script>
export default{
name: 'subScroll',
data(){
return {
start: 0
}
},
computed:{
copyDataList(){
return this.$props.dataList.slice(this.start, this.$props.rowCount + this.start)
}
},
props:{
dataList: {
type: Array,
default(){
return [{}]
}
},
rowCount: {
type: Number,
default: 0
},
rowHeight: {
type: Number,
default: 0
}
},
mounted(){
},
methods: {
onScroll(){
//全局节流函数
this.$throttle(this.updataData, 50)
},
updataData(){
let offsetTop = this.$refs.scrollView.scrollTop
let offsetNum = Math.round(offsetTop / this.$props.rowHeight)
this.start = offsetNum
this.$refs.list.style.transform = `translateY(${offsetTop}px)`
console.log('滑动的距离', offsetTop)
}
}
}
</script>
<style lang="less" scoped>
.scrollView{
width: 200px;
height: 400px;
overflow: auto;
position: relative;
.item{
height: var(--rowHeight);
}
.scrollBar{
height: var(--scrollBarHeight);
}
.list{
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
}
</style>