@coreui/vue-pro
Version:
UI Components Library for Vue.js
88 lines (84 loc) • 3.73 kB
JavaScript
var vue = require('vue');
const CVirtualScroller = vue.defineComponent({
name: 'CVirtualScroller',
props: {
/**
* Amount of visible items
*/
visibleItems: {
type: Number,
default: 10,
},
},
setup(props, { slots }) {
const virtualScrollRef = vue.ref();
const virtualScrollContentRef = vue.ref();
const currentItemIndex = vue.ref(1);
const itemHeight = vue.ref(0);
const itemsNumber = vue.ref(0);
const viewportPadding = vue.ref(0);
const buffer = vue.computed(() => Math.floor(props.visibleItems / 2));
const maxHeight = vue.computed(() => itemsNumber.value * itemHeight.value + 2 * viewportPadding.value);
const viewportHeight = vue.computed(() => Math.min(props.visibleItems, itemsNumber.value) * itemHeight.value +
2 * viewportPadding.value);
vue.onMounted(() => {
if (virtualScrollRef.value) {
viewportPadding.value = Number.parseFloat(getComputedStyle(virtualScrollRef.value).paddingTop);
// It's necessary to calculate heights of items
virtualScrollRef.value.dispatchEvent(new CustomEvent('scroll'));
}
});
const handleScroll = (scrollTop) => {
currentItemIndex.value =
itemHeight.value && Math.max(Math.ceil(scrollTop / itemHeight.value), 1);
};
return () => {
const children = slots.default
? Array.isArray(slots.default()[0].children)
? slots.default()[0].children
: slots.default()
: [];
itemsNumber.value = children && children.length > 0 ? children.length : 0;
return vue.h('div', {
class: ['virtual-scroller'],
onScroll: (event) => handleScroll(event.target.scrollTop),
style: {
height: `${viewportHeight.value}px`,
overflowY: 'auto',
},
ref: virtualScrollRef,
}, vue.h('div', {
class: 'virtual-scroller-content',
style: {
height: `${maxHeight.value}px`,
},
ref: virtualScrollContentRef,
}, children.map((slot, index) => index + 1 > Math.max(currentItemIndex.value - buffer.value, 0) &&
index + 1 <= currentItemIndex.value + props.visibleItems + buffer.value &&
vue.cloneVNode(slot, {
class: [
{
'virtual-scroller-item-preload': index + 1 > currentItemIndex.value + props.visibleItems ||
index + 1 < currentItemIndex.value,
},
],
style: {
...(currentItemIndex.value > buffer.value && {
transform: `translateY(${(currentItemIndex.value - buffer.value) * itemHeight.value}px)`,
}),
},
ref: (node) => {
if (itemHeight.value === 0 && node && node.offsetHeight) {
itemHeight.value =
node.offsetHeight +
Number.parseFloat(getComputedStyle(node).marginTop) +
Number.parseFloat(getComputedStyle(node).marginBottom);
}
},
}))));
};
},
});
exports.CVirtualScroller = CVirtualScroller;
//# sourceMappingURL=CVirtualScroller.js.map
;