Refactor #3965 - For VirtualScroller

pull/4034/head
Tuğçe Küçükoğlu 2023-06-06 14:38:49 +03:00
parent 5c47976d98
commit 99434c4c00
3 changed files with 216 additions and 181 deletions

View File

@ -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>

View File

@ -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[];
} }
/** /**

View File

@ -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>