antares/src/renderer/components/BaseVirtualScroll.vue

91 lines
2.5 KiB
Vue
Raw Normal View History

2020-06-11 23:34:38 +02:00
<template>
<div class="vscroll-holder">
2020-06-11 23:34:38 +02:00
<div
class="vscroll-spacer"
:style="{
opacity: 0,
clear: 'both',
height: topHeight + 'px'
}"
/>
<slot :items="visibleItems" />
<div
class="vscroll-spacer"
:style="{
opacity: 0,
clear: 'both',
height: bottomHeight + 'px'
}"
/>
</div>
</template>
<script>
export default {
name: 'BaseVirtualScroll',
props: {
items: Array,
itemHeight: Number,
visibleHeight: Number,
scrollElement: {
type: HTMLDivElement,
default: null
}
2020-06-11 23:34:38 +02:00
},
data () {
return {
topHeight: 0,
bottomHeight: 0,
visibleItems: [],
renderTimeout: null,
localScrollElement: null
2020-06-11 23:34:38 +02:00
};
},
watch: {
scrollElement () {
this.setScrollElement();
}
},
2020-06-11 23:34:38 +02:00
mounted () {
this.setScrollElement();
2020-06-11 23:34:38 +02:00
},
2022-04-21 14:39:24 +02:00
beforeUnmount () {
this.localScrollElement.removeEventListener('scroll', this.checkScrollPosition);
2020-06-11 23:34:38 +02:00
},
methods: {
checkScrollPosition (e) {
clearTimeout(this.renderTimeout);
2020-06-11 23:34:38 +02:00
this.renderTimeout = setTimeout(() => {
this.updateWindow(e);
}, 200);
2020-06-11 23:34:38 +02:00
},
updateWindow () {
const visibleItemsCount = Math.ceil(this.visibleHeight / this.itemHeight);
2020-06-11 23:34:38 +02:00
const totalScrollHeight = this.items.length * this.itemHeight;
const offset = 50;
2020-06-11 23:34:38 +02:00
const scrollTop = this.localScrollElement.scrollTop;
2020-06-11 23:34:38 +02:00
const firstVisibleIndex = Math.floor(scrollTop / this.itemHeight);
const lastVisibleIndex = firstVisibleIndex + visibleItemsCount;
const firstCutIndex = Math.max(firstVisibleIndex - offset, 0);
const lastCutIndex = lastVisibleIndex + offset;
this.visibleItems = this.items.slice(firstCutIndex, lastCutIndex);
2020-06-11 23:34:38 +02:00
this.topHeight = firstCutIndex * this.itemHeight;
this.bottomHeight = totalScrollHeight - this.visibleItems.length * this.itemHeight - this.topHeight;
},
setScrollElement () {
if (this.localScrollElement)
this.localScrollElement.removeEventListener('scroll', this.checkScrollPosition);
this.localScrollElement = this.scrollElement ? this.scrollElement : this.$el;
this.updateWindow();
this.localScrollElement.addEventListener('scroll', this.checkScrollPosition);
2020-06-11 23:34:38 +02:00
}
}
};
</script>