Refactor #3965 - For VirtualScroller
parent
5c47976d98
commit
99434c4c00
|
@ -0,0 +1,194 @@
|
||||||
|
<script>
|
||||||
|
import BaseComponent from 'primevue/basecomponent';
|
||||||
|
import { useStyle } from 'primevue/usestyle';
|
||||||
|
|
||||||
|
const styles = `
|
||||||
|
.p-virtualscroller {
|
||||||
|
position: relative;
|
||||||
|
contain: strict;
|
||||||
|
transform: translateZ(0);
|
||||||
|
will-change: scroll-position;
|
||||||
|
outline: 0 none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-virtualscroller-content {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
/* contain: content; */
|
||||||
|
min-height: 100%;
|
||||||
|
min-width: 100%;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-virtualscroller-spacer {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 1px;
|
||||||
|
width: 1px;
|
||||||
|
transform-origin: 0 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-virtualscroller .p-virtualscroller-loader {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-virtualscroller-loader.p-component-overlay {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-virtualscroller-loading-icon {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-virtualscroller-loading-icon.p-icon {
|
||||||
|
width: 2rem;
|
||||||
|
height: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-virtualscroller-horizontal > .p-virtualscroller-content {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inline */
|
||||||
|
.p-virtualscroller-inline .p-virtualscroller-content {
|
||||||
|
position: static;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const inlineStyles = {
|
||||||
|
root: { overflow: 'auto' }
|
||||||
|
};
|
||||||
|
|
||||||
|
const classes = {
|
||||||
|
root: ({ instance, props }) => [
|
||||||
|
'p-virtualscroller',
|
||||||
|
{
|
||||||
|
'p-virtualscroller-inline': props.inline,
|
||||||
|
'p-virtualscroller-both p-both-scroll': instance.isBoth(),
|
||||||
|
'p-virtualscroller-horizontal p-horizontal-scroll': instance.isHorizontal()
|
||||||
|
}
|
||||||
|
],
|
||||||
|
content: ({ instance }) => [
|
||||||
|
'p-virtualscroller-content',
|
||||||
|
{
|
||||||
|
'p-virtualscroller-loading': instance.d_loading
|
||||||
|
}
|
||||||
|
],
|
||||||
|
spacer: 'p-virtualscroller-spacer',
|
||||||
|
loader: ({ instance }) => [
|
||||||
|
'p-virtualscroller-loader',
|
||||||
|
{
|
||||||
|
'p-component-overlay': !instance.$slots.loader
|
||||||
|
}
|
||||||
|
],
|
||||||
|
loadingIcon: 'p-virtualscroller-loading-icon'
|
||||||
|
};
|
||||||
|
|
||||||
|
const { load: loadStyle } = useStyle(styles, { id: 'primevue_virtualscroller_style', manual: true });
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'BaseVirtualScroller',
|
||||||
|
extends: BaseComponent,
|
||||||
|
props: {
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
style: null,
|
||||||
|
class: null,
|
||||||
|
items: {
|
||||||
|
type: Array,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
itemSize: {
|
||||||
|
type: [Number, Array],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
scrollHeight: null,
|
||||||
|
scrollWidth: null,
|
||||||
|
orientation: {
|
||||||
|
type: String,
|
||||||
|
default: 'vertical'
|
||||||
|
},
|
||||||
|
numToleratedItems: {
|
||||||
|
type: Number,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
delay: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
resizeDelay: {
|
||||||
|
type: Number,
|
||||||
|
default: 10
|
||||||
|
},
|
||||||
|
lazy: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
loaderDisabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
columns: {
|
||||||
|
type: Array,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
showSpacer: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
showLoader: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
tabindex: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
inline: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
step: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
appendOnly: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
autoSize: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
css: {
|
||||||
|
classes,
|
||||||
|
inlineStyles,
|
||||||
|
loadStyle
|
||||||
|
},
|
||||||
|
provide() {
|
||||||
|
return {
|
||||||
|
$parentInstance: this
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
|
@ -308,6 +308,11 @@ export interface VirtualScrollerProps {
|
||||||
* @type {VirtualScrollerPassThroughOptions}
|
* @type {VirtualScrollerPassThroughOptions}
|
||||||
*/
|
*/
|
||||||
pt?: VirtualScrollerPassThroughOptions;
|
pt?: VirtualScrollerPassThroughOptions;
|
||||||
|
/**
|
||||||
|
* When enabled, it removes component related styles in the core.
|
||||||
|
* @defaultValue false
|
||||||
|
*/
|
||||||
|
unstyled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -408,7 +413,12 @@ export interface VirtualScrollerSlots {
|
||||||
/**
|
/**
|
||||||
* Custom loading icon template.
|
* Custom loading icon template.
|
||||||
*/
|
*/
|
||||||
loadingicon(): VNode[];
|
loadingicon(scope: {
|
||||||
|
/**
|
||||||
|
* Style class of the icon.
|
||||||
|
*/
|
||||||
|
class: string;
|
||||||
|
}): VNode[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<template v-if="!disabled">
|
<template v-if="!disabled">
|
||||||
<div :ref="elementRef" :class="containerClass" :tabindex="tabindex" :style="style" @scroll="onScroll" v-bind="ptm('root')">
|
<div :ref="elementRef" :class="containerClass" :tabindex="tabindex" :style="[style, sx('root')]" @scroll="onScroll" v-bind="ptm('root')" data-pc-name="virtualscroller">
|
||||||
<slot
|
<slot
|
||||||
name="content"
|
name="content"
|
||||||
:styleClass="contentClass"
|
:styleClass="cx('content')"
|
||||||
:items="loadedItems"
|
:items="loadedItems"
|
||||||
:getItemOptions="getOptions"
|
:getItemOptions="getOptions"
|
||||||
:loading="d_loading"
|
:loading="d_loading"
|
||||||
|
@ -18,21 +18,21 @@
|
||||||
:horizontal="isHorizontal()"
|
:horizontal="isHorizontal()"
|
||||||
:both="isBoth()"
|
:both="isBoth()"
|
||||||
>
|
>
|
||||||
<div :ref="contentRef" :class="contentClass" :style="contentStyle" v-bind="ptm('content')">
|
<div :ref="contentRef" :class="cx('content')" :style="contentStyle" v-bind="ptm('content')">
|
||||||
<template v-for="(item, index) of loadedItems" :key="index">
|
<template v-for="(item, index) of loadedItems" :key="index">
|
||||||
<slot name="item" :item="item" :options="getOptions(index)"></slot>
|
<slot name="item" :item="item" :options="getOptions(index)"></slot>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</slot>
|
</slot>
|
||||||
<div v-if="showSpacer" class="p-virtualscroller-spacer" :style="spacerStyle" v-bind="ptm('spacer')"></div>
|
<div v-if="showSpacer" :class="cx('spacer')" :style="spacerStyle" v-bind="ptm('spacer')"></div>
|
||||||
<div v-if="!loaderDisabled && showLoader && d_loading" :class="loaderClass" v-bind="ptm('loader')">
|
<div v-if="!loaderDisabled && showLoader && d_loading" :class="cx('loader')" v-bind="ptm('loader')">
|
||||||
<template v-if="$slots && $slots.loader">
|
<template v-if="$slots && $slots.loader">
|
||||||
<template v-for="(_, index) of loaderArr" :key="index">
|
<template v-for="(_, index) of loaderArr" :key="index">
|
||||||
<slot name="loader" :options="getLoaderOptions(index, isBoth() && { numCols: d_numItemsInViewport.cols })"></slot>
|
<slot name="loader" :options="getLoaderOptions(index, isBoth() && { numCols: d_numItemsInViewport.cols })"></slot>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
<slot name="loadingicon">
|
<slot name="loadingicon" :class="cx('loadingIcon')">
|
||||||
<SpinnerIcon spin class="p-virtualscroller-loading-icon" v-bind="ptm('loadingIcon')" />
|
<SpinnerIcon spin :class="cx('loadingIcon')" v-bind="ptm('loadingIcon')" />
|
||||||
</slot>
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -44,96 +44,14 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import BaseComponent from 'primevue/basecomponent';
|
|
||||||
import SpinnerIcon from 'primevue/icons/spinner';
|
import SpinnerIcon from 'primevue/icons/spinner';
|
||||||
import { DomHandler } from 'primevue/utils';
|
import { DomHandler } from 'primevue/utils';
|
||||||
|
import BaseVirtualScroller from './BaseVirtualScroller.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'VirtualScroller',
|
name: 'VirtualScroller',
|
||||||
extends: BaseComponent,
|
extends: BaseVirtualScroller,
|
||||||
emits: ['update:numToleratedItems', 'scroll', 'scroll-index-change', 'lazy-load'],
|
emits: ['update:numToleratedItems', 'scroll', 'scroll-index-change', 'lazy-load'],
|
||||||
props: {
|
|
||||||
id: {
|
|
||||||
type: String,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
style: null,
|
|
||||||
class: null,
|
|
||||||
items: {
|
|
||||||
type: Array,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
itemSize: {
|
|
||||||
type: [Number, Array],
|
|
||||||
default: 0
|
|
||||||
},
|
|
||||||
scrollHeight: null,
|
|
||||||
scrollWidth: null,
|
|
||||||
orientation: {
|
|
||||||
type: String,
|
|
||||||
default: 'vertical'
|
|
||||||
},
|
|
||||||
numToleratedItems: {
|
|
||||||
type: Number,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
delay: {
|
|
||||||
type: Number,
|
|
||||||
default: 0
|
|
||||||
},
|
|
||||||
resizeDelay: {
|
|
||||||
type: Number,
|
|
||||||
default: 10
|
|
||||||
},
|
|
||||||
lazy: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
disabled: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
loaderDisabled: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
columns: {
|
|
||||||
type: Array,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
loading: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
showSpacer: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
showLoader: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
tabindex: {
|
|
||||||
type: Number,
|
|
||||||
default: 0
|
|
||||||
},
|
|
||||||
inline: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
step: {
|
|
||||||
type: Number,
|
|
||||||
default: 0
|
|
||||||
},
|
|
||||||
appendOnly: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
autoSize: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
first: this.isBoth() ? { rows: 0, cols: 0 } : 0,
|
first: this.isBoth() ? { rows: 0, cols: 0 } : 0,
|
||||||
|
@ -686,7 +604,7 @@ export default {
|
||||||
return this.step ? this.page !== this.getPageByFirst(first ?? this.first) : true;
|
return this.step ? this.page !== this.getPageByFirst(first ?? this.first) : true;
|
||||||
},
|
},
|
||||||
setContentEl(el) {
|
setContentEl(el) {
|
||||||
this.content = el || this.content || DomHandler.findSingle(this.element, '.p-virtualscroller-content');
|
this.content = el || this.content || DomHandler.findSingle(this.element, '[data-pc-section="content"]');
|
||||||
},
|
},
|
||||||
elementRef(el) {
|
elementRef(el) {
|
||||||
this.element = el;
|
this.element = el;
|
||||||
|
@ -697,31 +615,7 @@ export default {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
containerClass() {
|
containerClass() {
|
||||||
return [
|
return [this.cx('root'), this.class];
|
||||||
'p-virtualscroller',
|
|
||||||
{
|
|
||||||
'p-virtualscroller-inline': this.inline,
|
|
||||||
'p-virtualscroller-both p-both-scroll': this.isBoth(),
|
|
||||||
'p-virtualscroller-horizontal p-horizontal-scroll': this.isHorizontal()
|
|
||||||
},
|
|
||||||
this.class
|
|
||||||
];
|
|
||||||
},
|
|
||||||
contentClass() {
|
|
||||||
return [
|
|
||||||
'p-virtualscroller-content',
|
|
||||||
{
|
|
||||||
'p-virtualscroller-loading': this.d_loading
|
|
||||||
}
|
|
||||||
];
|
|
||||||
},
|
|
||||||
loaderClass() {
|
|
||||||
return [
|
|
||||||
'p-virtualscroller-loader',
|
|
||||||
{
|
|
||||||
'p-component-overlay': !this.$slots.loader
|
|
||||||
}
|
|
||||||
];
|
|
||||||
},
|
},
|
||||||
loadedItems() {
|
loadedItems() {
|
||||||
if (this.items && !this.d_loading) {
|
if (this.items && !this.d_loading) {
|
||||||
|
@ -753,66 +647,3 @@ export default {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
|
||||||
.p-virtualscroller {
|
|
||||||
position: relative;
|
|
||||||
overflow: auto;
|
|
||||||
contain: strict;
|
|
||||||
transform: translateZ(0);
|
|
||||||
will-change: scroll-position;
|
|
||||||
outline: 0 none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.p-virtualscroller-content {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
/* contain: content; */
|
|
||||||
min-height: 100%;
|
|
||||||
min-width: 100%;
|
|
||||||
will-change: transform;
|
|
||||||
}
|
|
||||||
|
|
||||||
.p-virtualscroller-spacer {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
height: 1px;
|
|
||||||
width: 1px;
|
|
||||||
transform-origin: 0 0;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.p-virtualscroller .p-virtualscroller-loader {
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.p-virtualscroller-loader.p-component-overlay {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.p-virtualscroller-loading-icon {
|
|
||||||
font-size: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.p-virtualscroller-loading-icon.p-icon {
|
|
||||||
width: 2rem;
|
|
||||||
height: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.p-virtualscroller-horizontal > .p-virtualscroller-content {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Inline */
|
|
||||||
.p-virtualscroller-inline .p-virtualscroller-content {
|
|
||||||
position: static;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
Loading…
Reference in New Issue