vue长列表虚拟滚动封装
<template>
<div ref="virtual" class="virtual-empty" :style="{ height: height + 'px' }">
<div class="virtual-container" :style="{ height: clacHeight + 'px', minHeight: height + 'px' }">
<slot :topIndex="topIndex" :bottomIndex="bottomIndex"></slot>
</div>
</div>
</template>
<script>
export default {
name: 'VirtualScroll',
props: {
height: {
required: true,
type: Number,
default: 0
},
childHeight: {
required: true,
type: Number,
default: 0
},
offset: {
required: false,
type: Number,
default: 0
},
data: {
required: true,
type: Array,
default: () => []
}
},
data() {
return {
topIndex: 0,
bottomIndex: 0,
totalHeight: 0,
}
},
mounted() {
this.initScroll()
},
beforeDestroy() {
this.virtualDom.removeEventListener('scroll', this.debounceScroll, {passive: true})
this.virtualDom = null
},
computed: {
clacHeight() {
let length = this.data.length
let height = length > 0 ? length * this.childHeight > this.height ? length * this.childHeight : this.height : this.height
length = null
return height
}
},
methods: {
initScroll() {
if(!this.height) return
if(!this.childHeight) return
this.virtualDom = this.$refs['virtual']
this.debounceScroll = _.debounce(this.scroll, 16)
this.virtualDom.addEventListener('scroll', this.debounceScroll, {passive: true})
this.scroll()
},
scroll() {
let scrollTop = this.virtualDom.scrollTop
this.topIndex = Math.floor((scrollTop - this.offset > 0 ? scrollTop - this.offset : scrollTop) / this.childHeight);
this.bottomIndex = this.topIndex + Math.ceil((this.height + this.offset) / this.childHeight)
scrollTop = null
},
// 重制滚动高度
resetScrollTop() {
this.virtualDom.scrollTop = 0
}
}
}
</script>
<style lang="less">
.virtual-empty {
overflow-y: scroll;
}
.virtual-container {
position: relative;
width: 100%;
}
</style>