UNPKG

quasar

Version:

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

171 lines (135 loc) 4.48 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.js' import { getScrollTarget } from '../../utils/scroll.js' import { listenOpts } from '../../utils/event.js' import { hMergeSlot } from '../../utils/private/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: { default: void 0 } }, 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) } } })