Virtualization in Vue Listview component
11 Jun 202424 minutes to read
UI virtualization loads only viewable list items in a view port, which will improve the ListView performance while loading a large number of data.
Module injection
In order to use UI Virtualization, virtualization
module should be injected into the provide section and use listview
as a key of the object.
export default {
data: function() {
return {
listData: listData,
enableUi: true
};
},
provide: {
listview: [Virtualization]
}
}
Getting started
UI virtualization can be enabled in the ListView by setting the enableVirtualization
property to true.
It has two types of scrollers as follows:
Window scroll: This scroller is used in the ListView by default.
Container scroll: This scroller is used, when the height property of the ListView is set.
<template>
<div class="control-section">
<ejs-listview id='ui-list' :dataSource='listData' :enableVirtualization='enableUi'>
</ejs-listview>
</div>
</template>
<script setup>
import { provide, onBeforeMount } from "vue";
import { ListViewComponent as EjsListview, Virtualization } from "@syncfusion/ej2-vue-lists";
let listData = [];
onBeforeMount(() => {
listData = [
{ text: "Nancy", id: "0" },
{ text: "Andrew", id: "1" },
{ text: "Janet", id: "2" },
{ text: "Margaret", id: "3" },
{ text: "Steven", id: "4" },
{ text: "Laura", id: "5" },
{ text: "Robert", id: "6" },
{ text: "Michael", id: "7" },
{ text: "Albert", id: "8" },
{ text: "Nolan", id: "9" }
];
for (let i = 10; i <= 1000; i++) {
let index = parseInt((Math.random() * 10).toString());
listData.push({ text: listData[index].text, id: i.toString() });
}
});
const enableUi = true;
provide('listview', [Virtualization]);
</script>
<style>
#app {
color: #008cff;
height: 40px;
left: 30%;
position: absolute;
}
#ui-list {
display: block;
max-width: 400px;
margin: auto;
border-radius: 3px;
cursor: pointer;
}
</style>
<template>
<div class="control-section">
<ejs-listview id='ui-list' :dataSource='listData' :enableVirtualization='enableUi'>
</ejs-listview>
</div>
</template>
<script>
import { ListViewComponent, Virtualization } from "@syncfusion/ej2-vue-lists";
let listData = [];
export default {
name: "App",
components: {
"ejs-listview": ListViewComponent
},
beforeCreate: function () {
listData = [
{ text: "Nancy", id: "0" },
{ text: "Andrew", id: "1" },
{ text: "Janet", id: "2" },
{ text: "Margaret", id: "3" },
{ text: "Steven", id: "4" },
{ text: "Laura", id: "5" },
{ text: "Robert", id: "6" },
{ text: "Michael", id: "7" },
{ text: "Albert", id: "8" },
{ text: "Nolan", id: "9" }
];
for (let i = 10; i <= 1000; i++) {
let index = parseInt((Math.random() * 10).toString());
listData.push({ text: listData[index].text, id: i.toString() });
}
},
data: function () {
return {
listData: listData,
enableUi: true
};
},
provide: {
listview: [Virtualization]
}
};
</script>
<style>
#app {
color: #008cff;
height: 40px;
left: 30%;
position: absolute;
}
#ui-list {
display: block;
max-width: 400px;
margin: auto;
border-radius: 3px;
cursor: pointer;
}
</style>
Template
We can use template
property to customize list items in UI virtualization.
<template>
<div class="control-section">
<ejs-listview id='ui-list' ref="list" :dataSource='listData' :showHeader='header' :fields='fields'
:headerTitle='title' :height='height' :cssClass='cssClass' :enableVirtualization='enableUi'
:template="'gTemplate'">
<template v-slot:gTemplate="{ data }">
<div class="e-list-wrapper e-list-avatar">
<span :class="['e-avatar e-avatar-circle ' + data.icon + ' showUI']" v-if="data.imgUrl == undefined"></span>
<span :class="['e-avatar e-avatar-circle ' + data.icon + ' hideUI']" v-if="data.imgUrl !== undefined"></span>
<img :class="['e-avatar e-avatar-circle showUI']" :src="data.imgUrl" v-if="data.imgUrl !== undefined" />
<img :class="['e-avatar e-avatar-circle hideUI']" :src="data.imgUrl" v-if="data.imgUrl == undefined" />
<span class="e-list-content"></span>
</div>
</template>
</ejs-listview>
</div>
</template>
<script setup>
import { provide, onBeforeMount } from "vue";
import { ListViewComponent as EjsListview, Virtualization } from "@syncfusion/ej2-vue-lists";
let listData = [];
onBeforeMount(() => {
listData = [
{ name: 'Nancy', icon: 'N', id: '0', },
{ name: 'Andrew', icon: 'A', id: '1' },
{ name: 'Janet', icon: 'J', id: '2' },
{ name: 'Margaret', imgUrl: 'https://ej2.syncfusion.com/react/demos/src/listview/images/margaret.png', id: '3' },
{ name: 'Steven', icon: 'S', id: '4' },
{ name: 'Laura', imgUrl: 'https://ej2.syncfusion.com/react/demos/src/listview/images/laura.png', id: '5' },
{ name: 'Robert', icon: 'R', id: '6' },
{ name: 'Michael', icon: 'M', id: '7' },
{ name: 'Albert', imgUrl: 'https://ej2.syncfusion.com/react/demos/src/listview/images/albert.png', id: '8' },
{ name: 'Nolan', icon: 'N', id: '9' }
];
for (let i = 10; i <= 1000; i++) {
let index = parseInt((Math.random() * 10).toString());
listData.push({ name: listData[index].name, icon: listData[index].icon, imgUrl: listData[index].imgUrl, id: i.toString() });
}
});
const header = true;
const title = "Contacts";
const fields = { text: "name" };
const height = 500;
const cssClass = 'e-list-template';
const enableUi = true;
provide('listview', [Virtualization]);
</script>
<style>
@import "../node_modules/@syncfusion/ej2-base/styles/material.css";
@import "../node_modules/@syncfusion/ej2-buttons/styles/material.css";
@import "../node_modules/@syncfusion/ej2-vue-lists/styles/material.css";
#app {
color: #008cff;
height: 40px;
left: 30%;
position: absolute;
}
#ui-list.e-listview {
margin: auto;
max-width: 325px;
line-height: initial;
border: 1px solid lightgray;
}
/* ListView header alignment */
#ui-list.e-listview .e-list-header {
height: 50px
}
#ui-list.e-listview .e-list-header .e-text {
line-height: 18px
}
/* ListView template customization */
#ui-list.e-listview .showUI {
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
}
#ui-list.e-listview .hideUI {
display: none;
}
#ui-list.e-listview .e-list-item {
padding: 3px 0;
}
#ui-list.e-listview .R {
background: lightgrey;
}
#ui-list.e-listview .M {
background: pink;
}
#ui-list.e-listview .A {
background: lightgreen;
}
#ui-list.e-listview .S {
background: lightskyblue;
}
#ui-list.e-listview .J {
background: orange;
}
#ui-list.e-listview .N {
background: lightblue;
}
</style>
<template>
<div class="control-section">
<ejs-listview id='ui-list' ref="list" :dataSource='listData' :showHeader='header' :fields='fields' :headerTitle='title'
:height='height' :cssClass='cssClass' :enableVirtualization='enableUi' :template="'gTemplate'">
<template v-slot:gTemplate="{ data }">
<div class="e-list-wrapper e-list-avatar" >
<span :class="['e-avatar e-avatar-circle ' + data.icon + ' showUI']" v-if="data.imgUrl == undefined"></span>
<span :class="['e-avatar e-avatar-circle ' + data.icon + ' hideUI']" v-if="data.imgUrl !== undefined"></span>
<img :class="['e-avatar e-avatar-circle showUI']" :src="data.imgUrl" v-if="data.imgUrl !== undefined" />
<img :class="['e-avatar e-avatar-circle hideUI']" :src="data.imgUrl" v-if="data.imgUrl == undefined" />
<span class="e-list-content"></span>
</div>
</template>
</ejs-listview>
</div>
</template>
<script>
import { ListViewComponent, Virtualization } from "@syncfusion/ej2-vue-lists";
let listData = [];
export default {
name: "App",
components: {
"ejs-listview":ListViewComponent
},
beforeCreate: function() {
listData = [
{ name: 'Nancy', icon: 'N', id: '0', },
{ name: 'Andrew', icon: 'A', id: '1' },
{ name: 'Janet', icon: 'J', id: '2' },
{ name: 'Margaret', imgUrl: 'https://ej2.syncfusion.com/react/demos/src/listview/images/margaret.png', id: '3' },
{ name: 'Steven', icon: 'S', id: '4' },
{ name: 'Laura', imgUrl: 'https://ej2.syncfusion.com/react/demos/src/listview/images/laura.png', id: '5' },
{ name: 'Robert', icon: 'R', id: '6' },
{ name: 'Michael', icon: 'M', id: '7' },
{ name: 'Albert', imgUrl: 'https://ej2.syncfusion.com/react/demos/src/listview/images/albert.png', id: '8' },
{ name: 'Nolan', icon: 'N', id: '9' }
];
for (let i = 10; i <= 1000; i++) {
let index = parseInt((Math.random() * 10).toString());
listData.push({ name: listData[index].name, icon: listData[index].icon, imgUrl: listData[index].imgUrl, id: i.toString() });
}
},
data: function() {
return {
listData: listData,
header: true,
title: "Contacts",
fields: { text: "name" },
height: 500,
cssClass:'e-list-template',
enableUi: true,
};
},
provide: {
listview: [Virtualization]
}
}
</script>
<style>
@import "../node_modules/@syncfusion/ej2-base/styles/material.css";
@import "../node_modules/@syncfusion/ej2-buttons/styles/material.css";
@import "../node_modules/@syncfusion/ej2-vue-lists/styles/material.css";
#app {
color: #008cff;
height: 40px;
left: 30%;
position: absolute;
}
#ui-list.e-listview {
margin: auto;
max-width: 325px;
line-height: initial;
border: 1px solid lightgray;
}
/* ListView header alignment */
#ui-list.e-listview .e-list-header {
height: 50px
}
#ui-list.e-listview .e-list-header .e-text {
line-height: 18px
}
/* ListView template customization */
#ui-list.e-listview .showUI {
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
}
#ui-list.e-listview .hideUI {
display: none;
}
#ui-list.e-listview .e-list-item {
padding: 3px 0;
}
#ui-list.e-listview .R {
background: lightgrey;
}
#ui-list.e-listview .M {
background: pink;
}
#ui-list.e-listview .A {
background: lightgreen;
}
#ui-list.e-listview .S {
background: lightskyblue;
}
#ui-list.e-listview .J {
background: orange;
}
#ui-list.e-listview .N {
background: lightblue;
}
</style>
Conditional rendering
The following conditional rendering support is provided for the template and groupTemplate.
Name | Syntax |
---|---|
conditional class | <div class="${ $id % 2 === 0 ? 'even-list' : 'odd-list'}"></div> |
conditional attribute | <div id="${ $id % 2 === 0 ? 'even-list' : 'odd-list'}"></div> |
conditional text content | <div>${ $id % 2 === 0 ? 'even-list' : 'odd-list'}</div> |
In the following sample, the light blue is applied for the even list and light coral is applied for the odd list based on the conditional class.
<template>
<div class="control-section">
<ejs-listview id='ui-list' :dataSource='listData' :enableVirtualization='enableUi' :template='gTemplate'
:height='height'>
</ejs-listview>
</div>
</template>
<script setup>
import { provide } from "vue";
import { onBeforeMount } from "vue";
import { ListViewComponent as EjsListview, Virtualization } from "@syncfusion/ej2-vue-lists";
let listData = [];
onBeforeMount(() => {
listData = [
{ text: 'Nancy', id: '0', },
{ text: 'Andrew', id: '1' },
{ text: 'Janet', id: '2' },
{ text: 'Margaret', id: '3' },
{ text: 'Steven', id: '4' },
{ text: 'Laura', id: '5' },
{ text: 'Robert', id: '6' },
{ text: 'Michael', id: '7' },
{ text: 'Albert', id: '8' },
{ text: 'Nolan', id: '9' }
];
for (let i = 10; i <= 1000; i++) {
let index = parseInt((Math.random() * 10).toString());
listData.push({ text: listData[index].text, id: i.toString() });
}
});
const gTemplate = '<div id="list-container" class="${ $id % 2 === 0 ? \'even-list\' : \'odd-list\' }" > ${text} </div>';
const height = 500;
const enableUi = true;
provide('listview', [Virtualization]);
</script>
<style>
#app {
color: #008cff;
height: 40px;
left: 30%;
position: absolute;
}
#ui-list {
display: block;
max-width: 400px;
margin: auto;
border: 1px solid #dddddd;
border-radius: 3px;
cursor: pointer;
}
#list-container {
height: inherit;
width: inherit;
padding-left: 30px;
}
#ui-list .e-list-item {
padding: 0;
}
#ui-list .even-list {
background-color: lightblue;
}
#ui-list .odd-list {
background-color: lightcoral;
}
</style>
<template>
<div class="control-section">
<ejs-listview id='ui-list' :dataSource='listData' :enableVirtualization='enableUi' :template='gTemplate'
:height='height'>
</ejs-listview>
</div>
</template>
<script>
import { ListViewComponent, Virtualization } from "@syncfusion/ej2-vue-lists";
let listData = [];
export default {
name: "App",
components: {
"ejs-listview": ListViewComponent
},
beforeCreate: function () {
listData = [
{ text: 'Nancy', id: '0', },
{ text: 'Andrew', id: '1' },
{ text: 'Janet', id: '2' },
{ text: 'Margaret', id: '3' },
{ text: 'Steven', id: '4' },
{ text: 'Laura', id: '5' },
{ text: 'Robert', id: '6' },
{ text: 'Michael', id: '7' },
{ text: 'Albert', id: '8' },
{ text: 'Nolan', id: '9' }
];
for (let i = 10; i <= 1000; i++) {
let index = parseInt((Math.random() * 10).toString());
listData.push({ text: listData[index].text, id: i.toString() });
}
},
data: function () {
return {
listData: listData,
gTemplate: '<div id="list-container" class="${ $id % 2 === 0 ? \'even-list\' : \'odd-list\' }" > ${text} </div>',
height: 500,
enableUi: true,
};
},
provide: {
listview: [Virtualization]
}
}
</script>
<style>
#app {
color: #008cff;
height: 40px;
left: 30%;
position: absolute;
}
#ui-list {
display: block;
max-width: 400px;
margin: auto;
border: 1px solid #dddddd;
border-radius: 3px;
cursor: pointer;
}
#list-container {
height: inherit;
width: inherit;
padding-left: 30px;
}
#ui-list .e-list-item {
padding: 0;
}
#ui-list .even-list {
background-color: lightblue;
}
#ui-list .odd-list {
background-color: lightcoral;
}
</style>