As a developer, you’ve probably had to implement a big list or table for an app, either by loading lots of data without pagination, or using an infinite scroll pagination and scrolling several times through it. These lists or tables can become slow, especially when they have lots of elements, CSS styles and/or transitions.
vue-virtual-scroller is a Vue.js plugin that applies the virtual scroll technique in order to performantly render a list to the DOM, whether it’s a plain HTML ul li
list, a table, or a customized list.
Setup vue-virtual-scroller
After you have a basic Vue.js project created, start by installing the plugin from npm:
$ npm install -D vue-virtual-scroller
Then, in your main.js file you must include its CSS file and initialize it:
main.js
import "vue-virtual-scroller/dist/vue-virtual-scroller.css";import Vue from "vue";import VueVirtualScroller from "vue-virtual-scroller";Vue.use(VueVirtualScroller);// ...
That should be enough to start using it.
Creating a VirtualList
To start with a simple example, let’s create a plain list that takes lots of data and uses vue-virtual-scroller to render it.
Let’s use JSON-Generator to generate the JSON for 5000 entries and save it to a data.json file. You can use the following structure:
[ '{{repeat(5000)}}', { _id: '{{objectId()}}', age: '{{integer(20, 40)}}', name: '{{firstName()}} {{surname()}}', company: '{{company().toUpperCase()}}' }]
Let’s create a VirtualList.vue file, where we import data.json and add it to an items
component state property. Then, use the virtual-scroller
component, passing those items:
VirtualList.vue
template virtual-scroller :items="items" item-height="40" content-tag="ul" template slot-scope="props" li :key="props.itemKey"{{props.item.name}}/li /template /virtual-scroller/templatescriptimport items from "./data.json";export default { data: () = ({ items })};/script
We must set an item-height
to the virtual-scroller component. Alternatively, since we’re creating a list, we’ve set the content-tag="ul"
which will wrap the contents into a ul
tag.
vue-virtual-scroller allows to use scoped slots to render the contents for full flexibility with the rendering. By using slot-scope="props"
we have access to the virtual-scroller exposed data, and use it for rendering.
props
contains an itemKey
property that we should bind using :key="props.itemKey"
on the root of the content for performance reasons. Then we can access props.item
containing the raw item from the JSON we’ve passed through the items
property to virtual-scroller
.
If you’d like to style the elements in the list, you can add a class
attribute to the virtual-scroller
component, and access its contents:
template virtual-scroller .../virtual-scroller/templatestyle.virtual-list ul { list-style: none;}/style
Or, with scoped styles, use the /deep/
selector:
style scoped.virtual-list /deep/ ul { list-style: none;}/style
Creating a VirtualTable
Similar to the VirtualList component, let’s create a VirtualTable.vue file for a table:
VirtualTable.vue
template virtual-scroller :items="items" item-height="40" content-tag="table" template slot-scope="props" tr :key="props.itemKey" td{{props.item.age}}/td td{{props.item.name}}/td td{{props.item.company}}/td /tr /template /virtual-scroller/templatescriptimport items from "./data.json";export default { data: () = ({ items })};/script
We encounter a problem with this example; we want to add a thead
tag as the table header in order to show the columns names: Age, Name and Company.
Fortunately, virtual-scroller distributes its internal content using the following slots structure:
main slot name="before-container"/slot container slot name="before-content"/slot content !-- Your items here -- /content slot name="after-content"/slot /container slot name="after-container"/slot/main
Any of those slots can be used to place contents in there. container
will be replaced by the tag value of the container-tag
property, by default div
, and the content
by the content-tag
value.
It’s therefore easy to add a thead
using the before-content
slot:
template virtual-scroller :items="items" item-height="40" container-tag="table" content-tag="tbody" thead slot="before-content" tr tdAge/td tdName/td tdCompany/td /tr /thead template slot-scope="props" tr :key="props.itemKey" td{{props.item.age}}/td td{{props.item.name}}/td td{{props.item.company}}/td /tr /template /virtual-scroller/template
Notice that we’ve changed content-tag="table"
for container-tag="table"
and content-tag="tbody"
in order to keep a usual table structure, since now we’re using more elements.
I’m sure you can imagine how to add a tfoot
element as well .
Wrapping Up
We’ve used the vue-virtual-scroller plugin to create components for a VirtualList and a VirtualTable. If you try them out with the 5000 items we’ve generated, they should render and scroll quite smoothly. Check vue-virtual-scroller docs to see more options and customizations.
You can see the working code of the article in this Codesandox.
Stay cool