vuetify
Version:
Vue Material Component Framework
77 lines (76 loc) • 2.6 kB
JavaScript
// Utilities
import { computed, ref } from 'vue';
import { propsFactory } from "../../../util/index.mjs"; // Types
export const makeDataTableVirtualProps = propsFactory({
visibleItems: {
type: [String, Number],
default: 20
},
itemHeight: {
type: [String, Number],
default: 52
}
}, 'virtual');
const UP = -1;
const DOWN = 1;
// TODO: Replace this with composable from v-virtual-scroll
export function useVirtual(props, items) {
const startIndex = ref(0);
const itemHeight = computed(() => parseInt(props.itemHeight, 10));
const visibleItems = computed(() => parseInt(props.visibleItems, 10));
const containerRef = ref();
const isScrolling = ref(false);
function calculateOffset(index) {
return index * itemHeight.value;
}
function calculateMidPointIndex(scrollTop) {
let start = 0;
let end = items.value.length;
while (start <= end) {
const middle = start + Math.floor((end - start) / 2);
const middleOffset = calculateOffset(middle);
if (middleOffset === scrollTop) {
return middle;
} else if (middleOffset < scrollTop) {
start = middle + 1;
} else if (middleOffset > scrollTop) {
end = middle - 1;
}
}
return start;
}
let lastScrollTop = 0;
let scrollTimeout;
function handleScroll() {
if (!containerRef.value) return;
isScrolling.value = true;
clearTimeout(scrollTimeout);
scrollTimeout = setTimeout(() => {
isScrolling.value = false;
}, 100);
const scrollTop = containerRef.value.scrollTop;
const direction = scrollTop < lastScrollTop ? UP : DOWN;
const midPointIndex = calculateMidPointIndex(scrollTop);
const buffer = Math.round(visibleItems.value / 3);
if (direction === UP && midPointIndex <= startIndex.value) {
startIndex.value = Math.max(midPointIndex - buffer, 0);
} else if (direction === DOWN && midPointIndex >= startIndex.value + buffer * 2) {
startIndex.value = Math.min(Math.max(0, midPointIndex - buffer), items.value.length - visibleItems.value);
}
lastScrollTop = containerRef.value.scrollTop;
}
const stopIndex = computed(() => Math.min(items.value.length, startIndex.value + visibleItems.value));
const paddingTop = computed(() => calculateOffset(startIndex.value));
const paddingBottom = computed(() => calculateOffset(items.value.length) - calculateOffset(stopIndex.value));
return {
startIndex,
stopIndex,
paddingTop,
paddingBottom,
handleScroll,
containerRef,
itemHeight,
isScrolling
};
}
//# sourceMappingURL=virtual.mjs.map