UNPKG

@coreui/vue-pro

Version:

UI Components Library for Vue.js

88 lines (84 loc) 3.73 kB
'use strict'; 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