JSPM

  • Created
  • Published
  • Downloads 3648
  • Score
    100M100P100Q124662F
  • License MIT

Package Exports

  • vue-virtual-scroll-grid

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.

Demo

Features

  • Use virtual-scrolling / windowing to render the items, so the number of DOM nodes is kept 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-grid

Example

<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 0.
  pageSize: number;
}

Available Slots

There are 3 scoped slots: default, placeholder and probe.

Props of the default slot:

  • item: the loaded item that is used for rendering your item element/component.
  • 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.

Props of the placeholder slot:

  • 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 placeholder slot is optional. If missing, the space of unloaded items will be blank until they are loaded.

The probe slot has no prop. It is used to measure the visual size of grid item. You can pass the same element/component for the placeholder slot. If not provided, you must set a fixed height to grid-template-rows on your CSS grid, e.g. 200px. Otherwise, the view won't be rendered properly.

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