primevue-mirror/pages/virtualscroller/index.vue

243 lines
11 KiB
Vue

<template>
<div>
<div class="content-section introduction">
<div class="feature-intro">
<h1>VirtualScroller</h1>
<p>VirtualScroller is a performant approach to handle huge data efficiently.</p>
</div>
<AppDemoActions />
</div>
<div class="content-section implementation virtualscroller-demo">
<div class="card">
<h5 class="mb-0">Basic</h5>
<div class="flex align-items-center flex-wrap">
<div class="flex flex-column mr-3 mt-3">
<h6>Vertical</h6>
<VirtualScroller :items="basicItems" :itemSize="50">
<template v-slot:item="{ item, options }">
<div :class="['scroll-item p-2', { odd: options.odd }]" style="height: 50px">{{ item }}</div>
</template>
</VirtualScroller>
</div>
<div class="flex flex-column mr-3 mt-3">
<h6>Horizontal</h6>
<VirtualScroller :items="basicItems" :itemSize="50" orientation="horizontal">
<template v-slot:item="{ item, options }">
<div :class="['scroll-item p-2', { odd: options.odd }]" style="width: 50px">{{ item }}</div>
</template>
</VirtualScroller>
</div>
<div class="flex flex-column mr-3 mt-3">
<h6>Both</h6>
<VirtualScroller :items="multiItems" :itemSize="[50, 100]" orientation="both">
<template v-slot:item="{ item, options }">
<div :class="['scroll-item p-2', { odd: options.odd }]" style="height: 50px">
<template v-for="(el, index) of item" :key="index">
<div style="width: 100px">{{ el }}</div>
</template>
</div>
</template>
</VirtualScroller>
</div>
</div>
</div>
<div class="card">
<h5 class="mb-0">Scroll Delay</h5>
<div class="flex align-items-center flex-wrap">
<div class="flex flex-column mr-3 mt-3">
<h6>0ms Delay</h6>
<VirtualScroller :items="basicItems" :itemSize="50">
<template v-slot:item="{ item, options }">
<div :class="['scroll-item p-2', { odd: options.odd }]" style="height: 50px">{{ item }}</div>
</template>
</VirtualScroller>
</div>
<div class="flex flex-column mr-3 mt-3">
<h6>150ms Delay</h6>
<VirtualScroller :items="basicItems" :itemSize="50" :delay="150">
<template v-slot:item="{ item, options }">
<div :class="['scroll-item p-2', { odd: options.odd }]" style="height: 50px">{{ item }}</div>
</template>
</VirtualScroller>
</div>
<div class="flex flex-column mr-3 mt-3">
<h6>250ms Delay</h6>
<VirtualScroller :items="basicItems" :itemSize="50" :delay="250">
<template v-slot:item="{ item, options }">
<div :class="['scroll-item p-2', { odd: options.odd }]" style="height: 50px">{{ item }}</div>
</template>
</VirtualScroller>
</div>
</div>
</div>
<div class="card">
<h5 class="mb-0">Loading</h5>
<div class="flex align-items-center flex-wrap">
<div class="flex flex-column mr-3 mt-3">
<h6>Basic</h6>
<VirtualScroller :items="basicItems" :itemSize="50" showLoader :delay="250">
<template v-slot:item="{ item, options }">
<div :class="['scroll-item p-2', { odd: options.odd }]" style="height: 50px">{{ item }}</div>
</template>
</VirtualScroller>
</div>
<div class="flex flex-column mr-3 mt-3">
<h6>Templating</h6>
<VirtualScroller class="custom-loading" :items="basicItems" :itemSize="50" showLoader :delay="250">
<template v-slot:item="{ item, options }">
<div :class="['scroll-item p-2', { odd: options.odd }]" style="height: 50px">{{ item }}</div>
</template>
<template v-slot:loader="{ options }">
<div :class="['scroll-item p-2', { odd: options.odd }]" style="height: 50px">
<Skeleton :width="options.even ? '60%' : '50%'" height="1.3rem" />
</div>
</template>
</VirtualScroller>
</div>
</div>
</div>
<div class="card">
<h5 class="mb-0">Lazy</h5>
<div class="flex align-items-center flex-wrap">
<div class="flex flex-column mr-3 mt-3">
<VirtualScroller :items="lazyItems" :itemSize="50" showLoader :delay="250" :loading="lazyLoading" lazy @lazy-load="onLazyLoad">
<template v-slot:item="{ item, options }">
<div :class="['scroll-item p-2', { odd: options.odd }]" style="height: 50px">{{ item }}</div>
</template>
</VirtualScroller>
</div>
</div>
</div>
<div class="card">
<h5 class="mb-0">Template</h5>
<div class="flex align-items-center flex-wrap">
<div class="flex flex-column mr-3 mt-3">
<VirtualScroller class="custom-loading" :items="basicItems" :itemSize="25 * 7" showLoader :delay="250">
<template v-slot:item="{ item, options }">
<div :class="['custom-scroll-item scroll-item', { odd: options.odd }]">
<div class="flex align-items-center px-2" style="height: 25px">{{ `Item: ${item}` }}</div>
<div class="flex align-items-center px-2" style="height: 25px">{{ `Index: ${options.index}` }}</div>
<div class="flex align-items-center px-2" style="height: 25px">{{ `Count: ${options.count}` }}</div>
<div class="flex align-items-center px-2" style="height: 25px">{{ `First: ${options.first}` }}</div>
<div class="flex align-items-center px-2" style="height: 25px">{{ `Last: ${options.last}` }}</div>
<div class="flex align-items-center px-2" style="height: 25px">{{ `Even: ${options.even}` }}</div>
<div class="flex align-items-center px-2" style="height: 25px">{{ `Odd: ${options.odd}` }}</div>
</div>
</template>
<template v-slot:loader="{ options }">
<div :class="['custom-scroll-item scroll-item', { odd: options.odd }]">
<div class="flex align-items-center px-2" style="height: 25px"><Skeleton width="60%" height="1.2rem" /></div>
<div class="flex align-items-center px-2" style="height: 25px"><Skeleton width="50%" height="1.2rem" /></div>
<div class="flex align-items-center px-2" style="height: 25px"><Skeleton width="60%" height="1.2rem" /></div>
<div class="flex align-items-center px-2" style="height: 25px"><Skeleton width="50%" height="1.2rem" /></div>
<div class="flex align-items-center px-2" style="height: 25px"><Skeleton width="60%" height="1.2rem" /></div>
<div class="flex align-items-center px-2" style="height: 25px"><Skeleton width="50%" height="1.2rem" /></div>
<div class="flex align-items-center px-2" style="height: 25px"><Skeleton width="60%" height="1.2rem" /></div>
</div>
</template>
</VirtualScroller>
</div>
</div>
</div>
</div>
<VirtualScrollerDoc />
</div>
</template>
<script>
import VirtualScrollerDoc from './VirtualScrollerDoc.vue';
export default {
data() {
return {
basicItems: null,
multiItems: null,
lazyItems: null,
lazyLoading: false,
loadLazyTimeout: null
};
},
mounted() {
this.basicItems = Array.from({ length: 100000 }).map((_, i) => `Item #${i}`);
this.multiItems = Array.from({ length: 1000 }).map((_, i) => Array.from({ length: 1000 }).map((_j, j) => `Item #${i}_${j}`));
this.lazyItems = Array.from({ length: 100000 });
},
methods: {
onLazyLoad(event) {
this.lazyLoading = true;
if (this.loadLazyTimeout) {
clearTimeout(this.loadLazyTimeout);
}
//imitate delay of a backend call
this.loadLazyTimeout = setTimeout(() => {
const { first, last } = event;
const lazyItems = [...this.lazyItems];
for (let i = first; i < last; i++) {
lazyItems[i] = `Item #${i}`;
}
this.lazyItems = lazyItems;
this.lazyLoading = false;
}, Math.random() * 1000 + 250);
}
},
components: {
VirtualScrollerDoc
}
};
</script>
<style lang="scss" scoped>
.virtualscroller-demo {
::v-deep(.p-virtualscroller) {
height: 200px;
width: 200px;
border: 1px solid var(--surface-border);
.scroll-item {
background-color: var(--surface-card);
display: flex;
align-items: center;
}
.custom-scroll-item {
flex-direction: column;
align-items: stretch;
}
.odd {
background-color: var(--surface-ground);
}
}
::v-deep(.p-horizontal-scroll) {
.p-virtualscroller-content {
display: flex;
flex-direction: row;
}
.scroll-item {
writing-mode: vertical-lr;
}
}
::v-deep(.custom-loading > .p-virtualscroller-loader) {
display: block;
}
}
</style>