primevue-mirror/pages/virtualscroller/VirtualScrollerDoc.vue

1100 lines
49 KiB
Vue

<template>
<ClientOnly>
<AppDoc name="VirtualScrollerDemo" :sources="sources" github="virtualscroller/VirtualScrollerDemo.vue">
<h5>Imports</h5>
<pre v-code.script><code>
import VirtualScroller from 'primevue/virtualscroller';
</code></pre>
<h5>Import via CDN</h5>
<pre v-code><code>
&lt;script src="https://unpkg.com/primevue@^3/core/core.min.js"&gt;&lt;/script&gt;
</code></pre>
<h5>Getting Started</h5>
<p>
VirtualScroller is used to display huge data. It periodically adds special elements defined according to the scroll's position to the DOM. The <i>item</i> and <i>itemSize</i> properties and <i>item</i> template are required on component.
In addition, an initial array is required based on the total number of items to display.<br />
VirtualScroller automatically calculates how many items will be displayed in the view according to <i>itemSize</i> using a specified scroll height. Its scroll height can be adjusted with <i>scrollHeight</i> property or height property of
CSS.
</p>
<pre v-code><code><template v-pre>
&lt;VirtualScroller :items="basicItems" :itemSize="50"&gt;
&lt;template v-slot:item="{ item, options }"&gt;
&lt;div :class="['scroll-item p-2', {'odd': options.odd}]" style="height: 50px"&gt;{{ item }}&lt;/div&gt;
&lt;/template&gt;
&lt;/VirtualScroller&gt;
</template>
</code></pre>
<pre v-code.script><code>
export default {
data() {
return {
basicItems: null
}
},
mounted() {
this.basicItems = Array.from({ length: 100000 }).map((_, i) => `Item #${i}`);
}
}
</code></pre>
<h5>Loader</h5>
<p>VirtualScroller has a special loader. It can be activated with the <i>showLoader</i> property. In addition, <i>loader</i> template can be used to add custom loaders to item elements.</p>
<pre v-code><code><template v-pre>
&lt;VirtualScroller :items="basicItems" :itemSize="50" showLoader :delay="250"&gt;
&lt;template v-slot:item="{ item, options }"&gt;
&lt;div :class="['scroll-item p-2', {'odd': options.odd}]" style="height: 50px"&gt;{{ item }}&lt;/div&gt;
&lt;/template&gt;
&lt;template v-slot:loader="{ options }"&gt;
&lt;div :class="['scroll-item p-2', {'odd': options.odd}]" style="height: 50px" &gt;
&lt;Skeleton :width="options.even ? '60%' : '50%'" height="1.3rem" /&gt;
&lt;/div&gt;
&lt;/template&gt;
&lt;/VirtualScroller&gt;
</template>
</code></pre>
<h5>Lazy</h5>
<p>Lazy mode is handy to deal with large datasets, instead of loading the entire data, small chunks of data is loaded by invoking <i>lazy-load</i> event.</p>
<pre v-code><code><template v-pre>
&lt;VirtualScroller :items="lazyItems" :itemSize="50" showLoader :delay="250" :loading="lazyLoading" :lazy=true @lazy-load="onLazyLoad"&gt;
&lt;template v-slot:item="{ item, options }"&gt;
&lt;div :class="['scroll-item p-2', {'odd': options.odd}]" style="height: 50px"&gt;{{ item }}&lt;/div&gt;
&lt;/template&gt;
&lt;/VirtualScroller&gt;
</template>
</code></pre>
<pre v-code.script><code>
export default {
data() {
return {
lazyItems: null,
lazyLoading: false,
loadLazyTimeout: null,
}
},
mounted() {
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 &lt; last; i++) {
lazyItems[i] = `Item #${i}`;
}
this.lazyItems = lazyItems;
this.lazyLoading = false;
}, Math.random() * 1000 + 250);
}
}
}
</code></pre>
<h5>Properties</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>id</td>
<td>string</td>
<td>null</td>
<td>Unique identifier of the element.</td>
</tr>
<tr>
<td>style</td>
<td>any</td>
<td>null</td>
<td>Inline style of the component.</td>
</tr>
<tr>
<td>class</td>
<td>string</td>
<td>null</td>
<td>Style class of the component.</td>
</tr>
<tr>
<td>items</td>
<td>array</td>
<td>null</td>
<td>An array of objects to display.</td>
</tr>
<tr>
<td>itemSize</td>
<td>number / [number, number]</td>
<td>null</td>
<td>The height/width of item according to orientation.</td>
</tr>
<tr>
<td>scrollHeight</td>
<td>string</td>
<td>null</td>
<td>Height of the scroll viewport.</td>
</tr>
<tr>
<td>scrollWidth</td>
<td>string</td>
<td>null</td>
<td>Width of the scroll viewport.</td>
</tr>
<tr>
<td>orientation</td>
<td>string</td>
<td>'vertical'</td>
<td>The orientation of scrollbar, valid values are 'vertical', 'horizontal' and 'both'.</td>
</tr>
<tr>
<td>numToleratedItems</td>
<td>number</td>
<td>null</td>
<td>
Determines how many additional elements to add to the DOM outside of the view. <br />
According to the scrolls made up and down, extra items are added in a certain algorithm in the form of multiples of this number. <br />
Default value is half the number of items shown in the view.
</td>
</tr>
<tr>
<td>delay</td>
<td>number</td>
<td>0</td>
<td>Delay in scroll before new data is loaded.</td>
</tr>
<tr>
<td>lazy</td>
<td>boolean</td>
<td>false</td>
<td>Defines if data is loaded and interacted with in lazy manner.</td>
</tr>
<tr>
<td>disabled</td>
<td>boolean</td>
<td>false</td>
<td>If disabled, the VirtualScroller feature is eliminated and the content is displayed directly.</td>
</tr>
<tr>
<td>loaderDisabled</td>
<td>boolean</td>
<td>false</td>
<td>Used to implement a custom loader instead of using the loader feature in the VirtualScroller.</td>
</tr>
<tr>
<td>loading</td>
<td>boolean</td>
<td>false</td>
<td>Whether the data is loaded.</td>
</tr>
<tr>
<td>showSpacer</td>
<td>boolean</td>
<td>true</td>
<td>Used to implement a custom spacer instead of using the spacer feature in the VirtualScroller.</td>
</tr>
<tr>
<td>showLoader</td>
<td>boolean</td>
<td>false</td>
<td>Whether to show loader.</td>
</tr>
<tr>
<td>tabindex</td>
<td>number</td>
<td>0</td>
<td>Index of the element in tabbing order.</td>
</tr>
</tbody>
</table>
</div>
<h5>Events</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>scroll</td>
<td>event: Browser event</td>
<td>Callback to invoke when scroll position changes.</td>
</tr>
<tr>
<td>scroll-index-change</td>
<td>
event.first: First index of the new data range to be loaded.<br />
event.last: Last index of the new data range to be loaded.
</td>
<td>Callback to invoke when scroll position and item's range in view changes.</td>
</tr>
<tr>
<td>lazy-load</td>
<td>
event.first: First index of the new data range to be loaded.<br />
event.last: Last index of the new data range to be loaded.
</td>
<td>Callback to invoke in lazy mode to load new data.</td>
</tr>
</tbody>
</table>
</div>
<h5>Methods</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>scrollTo</td>
<td>
left: Left position of scroll. <br />
top: Top position of scroll <br />
behavior: Behavior of scroll, valid values are 'auto' and 'smooth'
</td>
<td>Scroll to move to a specific position.</td>
</tr>
<tr>
<td>scrollToIndex</td>
<td>
index: Index of item according to orientation mode. <br />
behavior: Behavior of scroll, valid values are 'auto' and 'smooth'
</td>
<td>Scroll to move to a specific item.</td>
</tr>
<tr>
<td>scrollInView</td>
<td>
index: Index of item according to orientation mode. <br />
to: Defines the location of the item in view, valid values are 'to-start' and 'to-end'. <br />
behavior: Behavior of scroll, valid values are 'auto' and 'smooth'
</td>
<td>It is used to move the specified index into the view. It is a method that will usually be needed when keyboard support is added to the virtualScroller component.</td>
</tr>
<tr>
<td>getRenderedRange</td>
<td>-</td>
<td>Returns the range of items added to the DOM.</td>
</tr>
</tbody>
</table>
</div>
<h5>Slots</h5>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Parameters</th>
</tr>
</thead>
<tbody>
<tr>
<td>content</td>
<td>
items: An array of objects to display.<br />
styleClass: Style class of the component<br />
contentRef: Referance of the content<br />
getItemOptions: Options of the items<br />
loading: Whether the data is loaded<br />
getLoaderOptions: Loader options of the items while the data is loading.<br />
itemSize: The height/width of item according to orientation.<br />
rows: The number of the rendered rows.<br />
columns: The number of the rendered columns.<br />
spacerStyle: The style of spacer element.<br />
contentStyle: The style of content element.<br />
vertical: Whether the orientation is vertical.<br />
horizontal: Whether the orientation is horizontal.<br />
both: Whether the orientation is both.<br />
</td>
</tr>
<tr>
<td>item</td>
<td>
item: Item instance<br />
options: Options of the item instance
</td>
</tr>
<tr>
<td>loader</td>
<td>options: Options of the loader items</td>
</tr>
</tbody>
</table>
</div>
<h5>Styling</h5>
<p>Following is the list of structural style classes, for theming classes visit <nuxt-link to="/theming">theming</nuxt-link> page.</p>
<div class="doc-tablewrapper">
<table class="doc-table">
<thead>
<tr>
<th>Name</th>
<th>Element</th>
</tr>
</thead>
<tbody>
<tr>
<td>p-virtualscroller</td>
<td>Container element.</td>
</tr>
<tr>
<td>p-virtualscroller-content</td>
<td>Content element.</td>
</tr>
<tr>
<td>p-virtualscroller-loader</td>
<td>Loader element.</td>
</tr>
</tbody>
</table>
</div>
<h5>Dependencies</h5>
<p>None.</p>
</AppDoc>
</ClientOnly>
</template>
<script>
export default {
data() {
return {
sources: {
'options-api': {
tabName: 'Options API Source',
content: `
<template>
<div class="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=true @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>
</template>
<script>
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: 10000 });
},
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);
}
}
}
<\\/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>
`
},
'composition-api': {
tabName: 'Composition API Source',
content: `
<template>
<div class="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=true @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>
</template>
<script>
import { ref, onMounted } from 'vue';
export default {
setup() {
const basicItems = ref(Array.from({ length: 100000 }).map((_, i) => \`Item #\${i}\`));
const multiItems = ref(Array.from({ length: 1000 }).map((_, i) => Array.from({ length: 1000 }).map((_j, j) => \`Item #\${i}_\${j}\`)));
const lazyItems = ref(Array.from({ length: 10000 }));
const lazyLoading = ref(false);
const loadLazyTimeout = ref(null);
const onLazyLoad = (event) => {
lazyLoading.value = true;
if (loadLazyTimeout.value) {
clearTimeout(loadLazyTimeout.value);
}
//imitate delay of a backend call
loadLazyTimeout.value = setTimeout(() => {
const { first, last } = event;
const _lazyItems = [...lazyItems.value];
for (let i = first; i < last; i++) {
_lazyItems[i] = \`Item #\${i}\`;
}
lazyItems.value = _lazyItems;
lazyLoading.value = false;
}, Math.random() * 1000 + 250);
}
return { basicItems, multiItems, lazyItems, lazyLoading, onLazyLoad }
},
methods: {
}
}
<\\/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>
`
},
'browser-source': {
tabName: 'Browser Source',
imports: `<script src="https://unpkg.com/primevue@^3/skeleton/skeleton.min.js"><\\/script>`,
content: `<div id="app">
<div class="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>
<p-virtualscroller :items="basicItems" :item-size="50">
<template v-slot:item="{ item, options }">
<div :class="['scroll-item p-2', {'odd': options.odd}]" style="height: 50px">{{ item }}</div>
</template>
</p-virtualscroller>
</div>
<div class="flex flex-column mr-3 mt-3">
<h6>Horizontal</h6>
<p-virtualscroller :items="basicItems" :item-size="50" orientation="horizontal">
<template v-slot:item="{ item, options }">
<div :class="['scroll-item p-2', {'odd': options.odd}]" style="width: 50px">{{ item }}</div>
</template>
</p-virtualscroller>
</div>
<div class="flex flex-column mr-3 mt-3">
<h6>Both</h6>
<p-virtualscroller :items="multiItems" :item-size="[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>
</p-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>
<p-virtualscroller :items="basicItems" :item-size="50">
<template v-slot:item="{ item, options }">
<div :class="['scroll-item p-2', {'odd': options.odd}]" style="height: 50px">{{ item }}</div>
</template>
</p-virtualscroller>
</div>
<div class="flex flex-column mr-3 mt-3">
<h6>150ms Delay</h6>
<p-virtualscroller :items="basicItems" :item-size="50" :delay="150">
<template v-slot:item="{ item, options }">
<div :class="['scroll-item p-2', {'odd': options.odd}]" style="height: 50px">{{ item }}</div>
</template>
</p-virtualscroller>
</div>
<div class="flex flex-column mr-3 mt-3">
<h6>250ms Delay</h6>
<p-virtualscroller :items="basicItems" :item-size="50" :delay="250">
<template v-slot:item="{ item, options }">
<div :class="['scroll-item p-2', {'odd': options.odd}]" style="height: 50px">{{ item }}</div>
</template>
</p-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>
<p-virtualscroller :items="basicItems" :item-size="50" show-loader :delay="250">
<template v-slot:item="{ item, options }">
<div :class="['scroll-item p-2', {'odd': options.odd}]" style="height: 50px">{{ item }}</div>
</template>
</p-virtualscroller>
</div>
<div class="flex flex-column mr-3 mt-3">
<h6>Templating</h6>
<p-virtualscroller class="custom-loading" :items="basicItems" :item-size="50" show-loader :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" >
<p-skeleton :width="options.even ? '60%' : '50%'" height="1.3rem"></p-skeleton>
</div>
</template>
</p-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">
<p-virtualscroller :items="lazyItems" :item-size="50" show-loader :delay="250" :loading="lazyLoading" :lazy=true @lazy-load="onLazyLoad">
<template v-slot:item="{ item, options }">
<div :class="['scroll-item p-2', {'odd': options.odd}]" style="height: 50px">{{ item }}</div>
</template>
</p-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">
<p-virtualscroller class="custom-loading" :items="basicItems" :item-size="25 * 7" show-loader :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"><p-skeleton width="60%" height="1.2rem"></p-skeleton></div>
<div class="flex align-items-center px-2" style="height: 25px"><p-skeleton width="50%" height="1.2rem"></p-skeleton></div>
<div class="flex align-items-center px-2" style="height: 25px"><p-skeleton width="60%" height="1.2rem"></p-skeleton></div>
<div class="flex align-items-center px-2" style="height: 25px"><p-skeleton width="50%" height="1.2rem"></p-skeleton></div>
<div class="flex align-items-center px-2" style="height: 25px"><p-skeleton width="60%" height="1.2rem"></p-skeleton></div>
<div class="flex align-items-center px-2" style="height: 25px"><p-skeleton width="50%" height="1.2rem"></p-skeleton></div>
<div class="flex align-items-center px-2" style="height: 25px"><p-skeleton width="60%" height="1.2rem"></p-skeleton></div>
</div>
</template>
</p-virtualscroller>
</div>
</div>
</div>
</div>
</div>
<script type="module">
const { createApp, ref, onMounted } = Vue;
const App = {
setup() {
const basicItems = ref(Array.from({ length: 100000 }).map((_, i) => \`Item #\${i}\`));
const multiItems = ref(Array.from({ length: 1000 }).map((_, i) => Array.from({ length: 1000 }).map((_j, j) => \`Item #\${i}_\${j}\`)));
const lazyItems = ref(Array.from({ length: 10000 }));
const lazyLoading = ref(false);
const loadLazyTimeout = ref(null);
const onLazyLoad = (event) => {
lazyLoading.value = true;
if (loadLazyTimeout.value) {
clearTimeout(loadLazyTimeout.value);
}
//imitate delay of a backend call
loadLazyTimeout.value = setTimeout(() => {
const { first, last } = event;
const _lazyItems = [...lazyItems.value];
for (let i = first; i < last; i++) {
_lazyItems[i] = \`Item #\${i}\`;
}
lazyItems.value = _lazyItems;
lazyLoading.value = false;
}, Math.random() * 1000 + 250);
}
return { basicItems, multiItems, lazyItems, lazyLoading, onLazyLoad }
},
components: {
"p-virtualscroller": primevue.virtualscroller,
"p-skeleton": primevue.skeleton
}
};
createApp(App)
.use(primevue.config.default)
.mount("#app");
<\\/script>
<style>
.virtualscroller-demo .p-virtualscroller {
height: 200px;
width: 200px;
border: 1px solid var(--surface-border);
}
.virtualscroller-demo .p-virtualscroller .scroll-item {
background-color: var(--surface-card);
display: flex;
align-items: center;
}
.virtualscroller-demo .p-virtualscroller .custom-scroll-item {
flex-direction: column;
align-items: stretch;
}
.virtualscroller-demo .p-virtualscroller .odd {
background-color: var(--surface-ground);
}
.virtualscroller-demo .p-horizontal-scroll .p-virtualscroller-content {
display: flex;
flex-direction: row;
}
.virtualscroller-demo .p-horizontal-scroll .scroll-item {
writing-mode: vertical-lr;
}
.virtualscroller-demo .custom-loading > .p-virtualscroller-loader {
display: block;
}
</style>
`
}
}
};
}
};
</script>