
Product
Introducing Repository Labels and Security Policies
Socket is introducing a new way to organize repositories and apply repository-specific security policies.
vue-virtual-scroller
Advanced tools
vue-virtual-scroller is a Vue.js component that allows for efficient rendering of large lists and grids by only rendering the visible items. This helps in improving performance and reducing memory usage.
Dynamic List Rendering
This feature allows for rendering a large list of items efficiently by only rendering the items that are currently visible. The `RecycleScroller` component is used to achieve this.
<template>
<RecycleScroller
:items="items"
:item-size="50"
key-field="id"
>
<template #default="{ item, index }">
<div class="item">
{{ item.name }}
</div>
</template>
</RecycleScroller>
</template>
<script>
import { RecycleScroller } from 'vue-virtual-scroller'
export default {
components: {
RecycleScroller
},
data() {
return {
items: Array.from({ length: 1000 }).map((_, i) => ({ id: i, name: `Item ${i}` }))
}
}
}
</script>
Dynamic Grid Rendering
This feature allows for rendering a large grid of items efficiently by only rendering the items that are currently visible. The `DynamicScrollerGrid` component is used to achieve this.
<template>
<DynamicScrollerGrid
:items="items"
:min-item-size="100"
key-field="id"
>
<template #default="{ item, index }">
<div class="item">
{{ item.name }}
</div>
</template>
</DynamicScrollerGrid>
</template>
<script>
import { DynamicScrollerGrid } from 'vue-virtual-scroller'
export default {
components: {
DynamicScrollerGrid
},
data() {
return {
items: Array.from({ length: 1000 }).map((_, i) => ({ id: i, name: `Item ${i}` }))
}
}
}
</script>
Horizontal Scrolling
This feature allows for horizontal scrolling of a large list of items. The `RecycleScroller` component is used with the `horizontal` prop to achieve this.
<template>
<RecycleScroller
:items="items"
:item-size="100"
key-field="id"
horizontal
>
<template #default="{ item, index }">
<div class="item">
{{ item.name }}
</div>
</template>
</RecycleScroller>
</template>
<script>
import { RecycleScroller } from 'vue-virtual-scroller'
export default {
components: {
RecycleScroller
},
data() {
return {
items: Array.from({ length: 1000 }).map((_, i) => ({ id: i, name: `Item ${i}` }))
}
}
}
</script>
react-virtualized is a library for React that provides components for efficiently rendering large lists and grids. It offers a wide range of features including windowing, dynamic heights, and more. Compared to vue-virtual-scroller, it is designed for React instead of Vue.js.
react-window is a lightweight library for React that provides components for efficiently rendering large lists and grids. It is similar to react-virtualized but with a smaller footprint and simpler API. Like react-virtualized, it is designed for React and not Vue.js.
vue-virtual-scroll-list is a Vue.js component for efficiently rendering large lists. It offers similar functionality to vue-virtual-scroller but with a different API and implementation. It is a good alternative for Vue.js developers looking for virtual scrolling solutions.
Blazing fast scrolling of any amount of data | Live demo | Video demo
For Vue 3 support, see here
npm install --save vue-virtual-scroller
⚠️ vue-virtual-scroller
now uses vue-observe-visibility to automatically refresh itself when shown to prevent display glitches. This means you need to include the Intersection Observer polyfill needed by vue-observe-visibility
for this to work in old browsers (like Internet Explorer).
Install all the components:
import Vue from 'vue'
import VueVirtualScroller from 'vue-virtual-scroller'
Vue.use(VueVirtualScroller)
Use specific components:
import Vue from 'vue'
import { RecycleScroller } from 'vue-virtual-scroller'
Vue.component('RecycleScroller', RecycleScroller)
⚠️ The line below should be included when importing the package:
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
<link rel="stylesheet" href="vue-virtual-scroller/dist/vue-virtual-scroller.css"/>
<script src="vue.js"></script>
<script src="vue-virtual-scroller/dist/vue-virtual-scroller.min.js"></script>
If Vue is detected, the plugin will be installed automatically. If not, install the component:
Vue.use(VueVirtualScroller)
Or register it with a custom name:
Vue.component('RecycleScroller', VueVirtualScroller.RecycleScroller)
There are several components provided by vue-virtual-scroller
:
RecycleScroller is a component that only renders the visible items in your list. It also re-uses components and dom elements to be as efficient and performant as possible.
DynamicScroller is a component that wraps the RecycleScroller component and extends its features to include dynamic size management. The main use case for this is when you do not know the size of the items in advance. The Dynamic Scroller automatically "discovers" item dimensions as it renders new items during scrolling.
DynamicScrollerItem must wrap each item in a DynamicScroller to handle size computations.
IdState is a mixin that ease the local state management in reused components inside a RecycleScroller.
RecycleScroller is a virtual scroller that only renders the visible items. As the user scrolls, RecycleScroller reuses all components and DOM nodes to maintain optimal performance.
Use the scoped slot to render each item in the list:
<template>
<RecycleScroller
class="scroller"
:items="list"
:item-size="32"
key-field="id"
v-slot="{ item }"
>
<div class="user">
{{ item.name }}
</div>
</RecycleScroller>
</template>
<script>
export default {
props: {
list: Array,
},
}
</script>
<style scoped>
.scroller {
height: 100%;
}
.user {
height: 32%;
padding: 0 12px;
display: flex;
align-items: center;
}
</style>
id
field on the items. This can be configured with the keyField
prop if you are using another field name.item
prop being updated without being re-created (use computed props or watchers to properly react to props changes!).key
on list content (but you should on all nested <img>
elements to prevent load glitches).hover
class instead of the :hover
state selector (e.g. .vue-recycle-scroller__item-view.hover
or .hover .some-element-inside-the-item-view
).Here is what the internals of RecycleScroller look like in vertical mode:
<RecycleScroller>
<!-- Wrapper element with a pre-calculated total height -->
<wrapper
:style="{ height: computedTotalHeight + 'px' }"
>
<!-- Each view is translated to the computed position -->
<view
v-for="view of pool"
:style="{ transform: 'translateY(' + view.computedTop + 'px)' }"
>
<!-- Your elements will be rendered here -->
<slot
:item="view.item"
:index="view.nr.index"
:active="view.nr.used"
/>
</view>
</wrapper>
</RecycleScroller>
When the user scrolls inside RecycleScroller, the views are mostly just moved around to fill the new visible space, and the default slot properties updated. That way we get the minimum amount of components/elements creation and destruction and we use the full power of Vue virtual-dom diff algorithm to optimize DOM operations!
items
: list of items you want to display in the scroller.direction
(default: 'vertical'
): scrolling direction, either 'vertical'
or 'horizontal'
.itemSize
(default: null
): display height (or width in horizontal mode) of the items in pixels used to calculate the scroll size and position. If it is set to null
(the default value), it will use variable size mode.gridItems
: display that many items on the same line to create a grid. You must put a value for itemSize
to use this prop (dynamic sizes are not supported).itemSecondarySize
: size in pixels (width in vertical mode, height in horizontal mode) of the items in the grid when gridItems
is set. If itemSecondarySize
is not set, it will use the value of itemSize
.minItemSize
: minimum size used if the height (or width in horizontal mode) of a item is unknown.sizeField
(default: 'size'
): field used to get the item's size in variable size mode.typeField
(default: 'type'
): field used to differentiate different kinds of components in the list. For each distinct type, a pool of recycled items will be created.keyField
(default: 'id'
): field used to identify items and optimize managing rendered views.pageMode
(default: false
): enable Page mode.prerender
(default: 0
): render a fixed number of items for Server-Side Rendering (SSR).buffer
(default: 200
): amount of pixel to add to edges of the scrolling visible area to start rendering items further away.emitUpdate
(default: false
): emit a 'update'
event each time the virtual scroller content is updated (can impact performance).listClass
(default: ''
): custom classes added to the item list wrapper.itemClass
(default: ''
): custom classes added to each item.listTag
(default: 'div'
): the element to render as the list's wrapper.itemTag
(default: 'div'
): the element to render as the list item (the direct parent of the default slot content).resize
: emitted when the size of the scroller changes.visible
: emitted when the scroller considers itself to be visible in the page.hidden
: emitted when the scroller is hidden in the page.update (startIndex, endIndex, visibleStartIndex, visibleEndIndex)
: emitted each time the views are updated, only if emitUpdate
prop is true
scroll-start
: emitted when the first item is rendered.scroll-end
: emitted when the last item is rendered.item
: item being rendered in a view.index
: reflects each item's position in the items
arrayactive
: whether or not the view is active. An active view is considered visible and being positioned by RecycleScroller
. An inactive view is not considered visible and is hidden from the user. Any rendering-related computations should be skipped if the view is inactive.<main>
<slot name="before"></slot>
<wrapper>
<!-- Reused view pools here -->
<slot name="empty"></slot>
</wrapper>
<slot name="after"></slot>
</main>
Example:
<RecycleScroller
class="scroller"
:items="list"
:item-size="32"
>
<template #before>
Hey! I'm a message displayed before the items!
</template>
<template v-slot="{ item }">
<div class="user">
{{ item.name }}
</div>
</template>
</RecycleScroller>
The page mode expands the virtual-scroller and uses the page viewport to compute which items are visible. That way, you can use it in a big page with HTML elements before or after (like a header and a footer). Set the page-mode
prop to true
:
<header>
<menu></menu>
</header>
<RecycleScroller page-mode>
<!-- ... -->
</RecycleScroller>
<footer>
Copyright 2017 - Cat
</footer>
⚠️ This mode can be performance heavy with a lot of items. Use with caution.
If the itemSize
prop is not set or is set to null
, the virtual scroller will switch to variable size mode. You then need to expose a number field on the item objects with the size of the item element.
⚠️ You still need to set the size of the items with CSS correctly (with classes for example).
Use the sizeField
prop (default is 'size'
) to set the field used by the scroller to get the size for each item.
Example:
const items = [
{
id: 1,
label: 'Title',
size: 64,
},
{
id: 2,
label: 'Foo',
size: 32,
},
{
id: 3,
label: 'Bar',
size: 32,
},
]
You can set the buffer
prop (in pixels) on the virtual-scroller to extend the viewport considered when determining the visible items. For example, if you set a buffer of 1000 pixels, the virtual-scroller will start rendering items that are 1000 pixels below the bottom of the scroller visible area, and will keep the items that are 1000 pixels above the top of the visible area.
The default value is 200
.
<RecycleScroller :buffer="200" />
The prerender
props can be set as the number of items to render on the server inside the virtual scroller:
<RecycleScroller
:items="items"
:item-size="42"
:prerender="10"
>
This works just like the RecycleScroller, but it can render items with unknown sizes!
<template>
<DynamicScroller
:items="items"
:min-item-size="54"
class="scroller"
>
<template v-slot="{ item, index, active }">
<DynamicScrollerItem
:item="item"
:active="active"
:size-dependencies="[
item.message,
]"
:data-index="index"
>
<div class="avatar">
<img
:src="item.avatar"
:key="item.avatar"
alt="avatar"
class="image"
>
</div>
<div class="text">{{ item.message }}</div>
</DynamicScrollerItem>
</template>
</DynamicScroller>
</template>
<script>
export default {
props: {
items: Array,
},
}
</script>
<style scoped>
.scroller {
height: 100%;
}
</style>
minItemSize
is required for the initial render of items.DynamicScroller
won't detect size changes on its own, but you can put values that can affect the item size with size-dependencies
on DynamicScrollerItem.size
field on the items.Extends all the RecycleScroller props.
sizeField
prop since all the size management is done internally.Extends all the RecycleScroller events.
Extends all the RecycleScroller scoped slot props.
Extends all the RecycleScroller other slots.
The component that should wrap all the items in a DynamicScroller.
item
(required): the item rendered in the scroller.active
(required): is the holding view active in RecycleScroller. Will prevent unnecessary size recomputation.sizeDependencies
: values that can affect the size of the item. This prop will be watched and if one value changes, the size will be recomputed. Recommended instead of watchData
.watchData
(default: false
): deeply watch item
for changes to re-calculate the size (not recommended, can impact performance).tag
(default: 'div'
): element used to render the component.emitResize
(default: false
): emit the resize
event each time the size is recomputed (can impact performance).resize
: emitted each time the size is recomputed, only if emitResize
prop is true
.This is convenience mixin that can replace data
in components being rendered in a RecycleScroller.
Since the components in RecycleScroller are reused, you can't directly use the Vue standard data
properties: otherwise they will be shared with different items in the list!
IdState will instead provide an idState
object which is equivalent to $data
, but it's linked to a single item with its identifier (you can change which field with idProp
param).
In this example, we use the id
of the item
to have a "scoped" state to the item:
<template>
<div class="question">
<p>{{ item.question }}</p>
<button @click="idState.replyOpen = !idState.replyOpen">Reply</button>
<textarea
v-if="idState.replyOpen"
v-model="idState.replyText"
placeholder="Type your reply"
/>
</div>
</template>
<script>
import { IdState } from 'vue-virtual-scroller'
export default {
mixins: [
IdState({
// You can customize this
idProp: vm => vm.item.id,
}),
],
props: {
// Item in the list
item: Object,
},
// This replaces data () { ... }
idState () {
return {
replyOpen: false,
replyText: '',
}
},
}
</script>
idProp
(default: vm => vm.item.id
): field name on the component (for example: 'id'
) or function returning the id.FAQs
Smooth scrolling for any amount of data
We found that vue-virtual-scroller demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Product
Socket is introducing a new way to organize repositories and apply repository-specific security policies.
Research
Security News
Socket researchers uncovered malicious npm and PyPI packages that steal crypto wallet credentials using Google Analytics and Telegram for exfiltration.
Product
Socket now supports .NET, bringing supply chain security and SBOM accuracy to NuGet and MSBuild-powered C# projects.