Package Exports
- vue-virtual-scroll-grid
- vue-virtual-scroll-grid/dist/style.css
Readme
Virtual Scroll Grid for Vue 3
This is a reusable component for Vue 3 that renders a list with a huge number of items (e.g. 1000+ items) as a grid in a performant way.
Features
- Use virtual-scrolling / windowing to render the items, so the number of DOM nodes is low.
- Support using a paginated API to load the items in the background.
- Support placeholders for unloaded items and loaded items are cached for better performance.
- Just use CSS grid to style your grid. Minimum styling opinions form the library.
Install
npm istall vue-virtual-scroll-gridExmaple
<template>
<!-- length: The number of items in the list. -->
<!-- pageSize: The number of items in a page from the item provider (e.g. a backend API). -->
<!-- pageProvider: The callback that returns a page of items as a promise. -->
<Grid :length="1000" :pageSize="2" :pageProvider="pageProvider" class="grid">
<!-- When the item is not loaded, a placeholder is rendered -->
<template v-slot:placeholder="{ index, style }">
<div class="item" :style="style">
Placeholder {{ index }}
</div>
</template>
<!-- Render a loaded item -->
<template v-slot:default="{ item, style, index }">
<div class="item" :style="style">
{{ item }} {{ index }}
</div>
</template>
</Grid>
</template>
<script>
import Grid from "vue-virtual-scroll-grid";
export default {
name : "App",
components: {Grid},
setup : () => ({
// Return items for the given page after a 0-3 second randomly
pageProvider: (pageNumber, pageSize) =>
new Promise((resolve) =>
setTimeout(
() => resolve(new Array(pageSize).fill("Loaded Item")),
Math.round(3000 * Math.random())
)
),
}),
};
</script>
<style>
.grid {
display: grid;
grid-gap: 20px;
grid-template-rows: 200px;
grid-template-columns: repeat(2, 1fr);
place-items: stretch;
}
@media (min-width: 768px) {
.grid {
grid-template-columns: repeat(3, 1fr);
}
}
@media (min-width: 992px) {
.grid {
grid-template-columns: repeat(4, 1fr);
}
}
@media (min-width: 1280px) {
.grid {
grid-template-columns: repeat(4, 1fr);
}
}
@media (min-width: 1440px) {
.grid {
grid-template-columns: repeat(5, 1fr);
}
}
@media (min-width: 1650px) {
.grid {
grid-template-columns: repeat(6, 1fr);
}
}
@media (min-width: 1890px) {
.grid {
grid-template-columns: repeat(7, 1fr);
}
}
@media (min-width: 2530px) {
.grid {
grid-template-columns: repeat(8, 1fr);
}
}
.item {
box-sizing: border-box;
border: 1px solid black;
display: flex;
justify-content: center;
align-items: center;
}
</style>Caveats
The library does not require items have foreknown width and height, but do require them to be styled with the same width and height under a view. E.g. the items can be 200px x 200px when the view is under 768px and 300px x 500px above 768px.
Available Props
interface Props {
// The number of items in the list,
// must be an integer and greater than or equal to 0.
length: number;
// The callback that returns a page of items as a promise.
pageProvider: (pageNumber: number, pageSize: number) => Promise<unknown[]>
// The number of items in a page from the item provider (e.g. a backend API),
// must be an integer and greater than or equal to 0.
pageSize: number;
}Available Scoped Slots
There are 2 scoped slots: default and placeholder. Both of them have the
following slot props:
index: the index of current item within the list.style: the style object provided by the library that need to be set on the item element/component.
The default slot has an extra prop item, which is the loaded item that is
used for rendering your item element/component.
Development
- Setup
npm install - Run dev server
shell npm run dev - Lint (type check)
shell npm run lint - Build the library
shell npm run build - Build the demo
shell npm run build -- --mode=demo - Preview the locally built demo
shell npm run serve