UNPKG

quasar

Version:

Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time

221 lines (185 loc) 4.95 kB
import { h, ref, computed, watch, onBeforeMount, onMounted, onBeforeUnmount, onActivated, onDeactivated } from 'vue' import QList from '../item/QList.js' import QMarkupTable from '../markup-table/QMarkupTable.js' import getTableMiddle from '../table/get-table-middle.js' import { useVirtualScroll, useVirtualScrollProps } from './use-virtual-scroll.js' import { createComponent } from '../../utils/private.create/create.js' import { getScrollTarget, scrollTargetProp } from '../../utils/scroll/scroll.js' import { listenOpts } from '../../utils/event/event.js' import { hMergeSlot } from '../../utils/private.render/render.js' const comps = { list: QList, table: QMarkupTable } const typeOptions = ['list', 'table', '__qtable'] export default createComponent({ name: 'QVirtualScroll', props: { ...useVirtualScrollProps, type: { type: String, default: 'list', validator: v => typeOptions.includes(v) }, items: { type: Array, default: () => [] }, itemsFn: Function, itemsSize: Number, scrollTarget: scrollTargetProp }, setup(props, { slots, attrs }) { let localScrollTarget const rootRef = ref(null) const virtualScrollLength = computed(() => props.itemsSize >= 0 && props.itemsFn !== void 0 ? parseInt(props.itemsSize, 10) : Array.isArray(props.items) ? props.items.length : 0 ) const { virtualScrollSliceRange, localResetVirtualScroll, padVirtualScroll, onVirtualScrollEvt } = useVirtualScroll({ virtualScrollLength, getVirtualScrollTarget, getVirtualScrollEl }) const virtualScrollScope = computed(() => { if (virtualScrollLength.value === 0) { return [] } const mapFn = (item, i) => ({ index: virtualScrollSliceRange.value.from + i, item }) return props.itemsFn === void 0 ? props.items .slice( virtualScrollSliceRange.value.from, virtualScrollSliceRange.value.to ) .map(mapFn) : props .itemsFn( virtualScrollSliceRange.value.from, virtualScrollSliceRange.value.to - virtualScrollSliceRange.value.from ) .map(mapFn) }) const classes = computed( () => 'q-virtual-scroll q-virtual-scroll' + (props.virtualScrollHorizontal === true ? '--horizontal' : '--vertical') + (props.scrollTarget !== void 0 ? '' : ' scroll') ) const attributes = computed(() => props.scrollTarget !== void 0 ? {} : { tabindex: 0 } ) watch(virtualScrollLength, () => { localResetVirtualScroll() }) watch( () => props.scrollTarget, () => { unconfigureScrollTarget() configureScrollTarget() } ) function getVirtualScrollEl() { return rootRef.value.$el || rootRef.value } function getVirtualScrollTarget() { return localScrollTarget } function configureScrollTarget() { localScrollTarget = getScrollTarget( getVirtualScrollEl(), props.scrollTarget ) localScrollTarget.addEventListener( 'scroll', onVirtualScrollEvt, listenOpts.passive ) } function unconfigureScrollTarget() { if (localScrollTarget !== void 0) { localScrollTarget.removeEventListener( 'scroll', onVirtualScrollEvt, listenOpts.passive ) localScrollTarget = void 0 } } function __getVirtualChildren() { let child = padVirtualScroll( props.type === 'list' ? 'div' : 'tbody', virtualScrollScope.value.map(slots.default) ) if (slots.before !== void 0) { child = slots.before().concat(child) } return hMergeSlot(slots.after, child) } onBeforeMount(() => { localResetVirtualScroll() }) onMounted(() => { configureScrollTarget() }) onActivated(() => { configureScrollTarget() }) onDeactivated(() => { unconfigureScrollTarget() }) onBeforeUnmount(() => { unconfigureScrollTarget() }) return () => { if (slots.default === void 0) { console.error( 'QVirtualScroll: default scoped slot is required for rendering' ) return } return props.type === '__qtable' ? getTableMiddle( { ref: rootRef, class: 'q-table__middle ' + classes.value }, __getVirtualChildren() ) : h( comps[props.type], { ...attrs, ref: rootRef, class: [attrs.class, classes.value], ...attributes.value }, __getVirtualChildren ) } } })