Membuat Daftar Ter-virtualisasi/Jendela Geser Sederhana: Panduan Lengkap
Daftar ter-virtualisasi, juga dikenal sebagai jendela geser (sliding window), adalah teknik pengoptimalan performa yang digunakan untuk menampilkan data dalam jumlah besar secara efisien. Teknik ini hanya me-render item yang terlihat di layar, dan saat pengguna melakukan scroll, item baru dirender dan yang lama didaur ulang. Hal ini secara signifikan mengurangi DOM (Document Object Model) dan meningkatkan performa, terutama untuk daftar dengan ribuan atau jutaan item.
Mengapa Menggunakan Daftar Ter-virtualisasi?
Sebelum kita masuk ke implementasi, mari pahami mengapa kita memerlukan daftar ter-virtualisasi:
- Performa yang Ditingkatkan: Daftar tradisional me-render semua item sekaligus, yang dapat membebani browser dan menyebabkan kelambatan saat daftar bertambah besar. Daftar ter-virtualisasi hanya me-render item yang terlihat, sehingga meminimalkan beban perenderan.
- Penggunaan Memori yang Lebih Rendah: Dengan hanya menyimpan item yang terlihat di memori, penggunaan memori berkurang secara signifikan, yang sangat penting untuk perangkat seluler dan aplikasi web.
- Pengalaman Pengguna yang Lebih Baik: Daftar ter-virtualisasi menyediakan pengalaman scrolling yang lancar dan responsif, bahkan untuk daftar yang sangat besar.
- Efisiensi Biaya: Jika data diambil dari API, daftar ter-virtualisasi membantu mengurangi beban server dan biaya transfer data karena hanya data yang diperlukan yang diminta.
Konsep Utama Daftar Ter-virtualisasi
Sebelum kita mulai membuat daftar ter-virtualisasi sederhana, mari bahas konsep utama:
- Ukuran Jendela (Window Size): Jumlah item yang dirender dan ditampilkan secara bersamaan.
- Tinggi Item (Item Height): Tinggi setiap item dalam daftar. Penting untuk menghitung offset scroll dengan benar.
- Offset Scroll: Jarak scroll dari atas daftar. Ini digunakan untuk menentukan item mana yang akan dirender.
- Item Terlihat (Visible Items): Array item yang saat ini ditampilkan dalam jendela.
- Buffer: Jumlah item tambahan untuk dirender di atas dan di bawah jendela yang terlihat. Ini membantu mencegah artefak perenderan saat scrolling cepat.
Kerangka Implementasi: Langkah demi Langkah
Berikut adalah pendekatan langkah demi langkah untuk membuat daftar ter-virtualisasi sederhana:
- Struktur Dasar HTML: Buat struktur HTML dasar untuk daftar.
- Styling CSS: Atur styling untuk daftar dan item untuk memastikan tampilan yang benar.
- Pengaturan Data: Siapkan data yang akan ditampilkan dalam daftar.
- Logika Virtualisasi: Implementasikan logika virtualisasi untuk menghitung item yang terlihat berdasarkan posisi scroll.
- Perenderan Item: Buat fungsi untuk me-render item yang terlihat.
- Penanganan Scroll: Tambahkan event listener untuk menangani event scroll dan memperbarui item yang terlihat.
Langkah 1: Struktur Dasar HTML
Kita mulai dengan struktur HTML dasar:
<div class="virtualized-list-container">
<div class="virtualized-list-scroll-area">
<div class="virtualized-list-content">
<!-- Item will be rendered here -->
</div>
</div>
</div>
Penjelasan:
virtualized-list-container
: Kontainer utama untuk daftar.virtualized-list-scroll-area
: Area yang dapat di-scroll. Tingginya menentukan tinggi daftar total.virtualized-list-content
: Kontainer untuk item yang dirender. Posisi absolut dan transformasi digunakan untuk memosisikan item dengan benar.
Langkah 2: Styling CSS
Berikut adalah CSS untuk styling daftar:
.virtualized-list-container {
width: 300px;
height: 400px;
overflow: auto;
position: relative;
border: 1px solid #ccc;
}
.virtualized-list-scroll-area {
width: 100%;
height: 1000px; /* Tinggi dinamis berdasarkan jumlah item */
position: relative;
}
.virtualized-list-content {
position: absolute;
top: 0;
left: 0;
width: 100%;
}
.virtualized-list-item {
padding: 10px;
border-bottom: 1px solid #eee;
}
Penjelasan:
virtualized-list-container
: Mengatur tinggi dan lebar daftar, mengaktifkan scrolling, dan menyediakan konteks posisi.virtualized-list-scroll-area
: Mengatur tinggi total daftar, yang memungkinkan scrolling yang benar.virtualized-list-content
: Diposisikan secara absolut di dalam area scroll.virtualized-list-item
: Styling untuk setiap item dalam daftar.
Langkah 3: Pengaturan Data
Mari buat data yang akan kita tampilkan:
const totalItems = 1000;
const itemHeight = 50;
const items = Array.from({ length: totalItems }, (_, index) => ({
id: index,
text: `Item ${index + 1}`
}));
Penjelasan:
totalItems
: Jumlah total item dalam daftar.itemHeight
: Tinggi setiap item (penting untuk perhitungan).items
: Array data item. Setiap item memilikiid
dantext
.
Langkah 4: Logika Virtualisasi
Ini adalah inti dari daftar ter-virtualisasi. Kita menghitung item mana yang terlihat berdasarkan posisi scroll:
function getVisibleItems(scrollTop, itemHeight, items, containerHeight) {
const startIndex = Math.max(0, Math.floor(scrollTop / itemHeight));
const endIndex = Math.min(items.length, startIndex + Math.ceil(containerHeight / itemHeight));
return items.slice(startIndex, endIndex);
}
Penjelasan:
getVisibleItems
: Fungsi yang menghitung item yang terlihat.scrollTop
: Posisi scroll vertikal.itemHeight
: Tinggi setiap item.items
: Array data item.containerHeight
: Tinggi kontainer daftar.startIndex
: Indeks item pertama yang terlihat.endIndex
: Indeks item terakhir yang terlihat.slice
: Digunakan untuk mengekstrak item yang terlihat dari array data.
Langkah 5: Perenderan Item
Sekarang, kita membuat fungsi untuk me-render item yang terlihat:
function renderItems(visibleItems, itemHeight, scrollTop) {
const content = document.querySelector('.virtualized-list-content');
content.innerHTML = visibleItems.map(item => `
<div class="virtualized-list-item" style="height: ${itemHeight}px; top: ${item.id * itemHeight - scrollTop}px;">
${item.text}
</div>
`).join('');
}
Penjelasan:
renderItems
: Fungsi yang me-render item yang terlihat ke dalam DOM.visibleItems
: Array item yang akan dirender.itemHeight
: Tinggi setiap item.scrollTop
: Posisi scroll vertikal.map
: Digunakan untuk membuat HTML untuk setiap item.join
: Digunakan untuk menggabungkan HTML item ke dalam satu string.top
: Digunakan untuk memposisikan item dengan benar menggunakan properti offset.
Langkah 6: Penanganan Scroll
Terakhir, kita menambahkan event listener untuk menangani event scroll:
function initializeVirtualizedList() {
const container = document.querySelector('.virtualized-list-container');
const scrollArea = document.querySelector('.virtualized-list-scroll-area');
const content = document.querySelector('.virtualized-list-content');
scrollArea.style.height = `${totalItems * itemHeight}px`;
function handleScroll() {
const scrollTop = container.scrollTop;
const containerHeight = container.clientHeight;
const visibleItems = getVisibleItems(scrollTop, itemHeight, items, containerHeight);
renderItems(visibleItems, itemHeight, scrollTop);
}
container.addEventListener('scroll', handleScroll);
// Inisialisasi perenderan
handleScroll();
}
// Panggil fungsi inisialisasi saat dokumen dimuat
document.addEventListener('DOMContentLoaded', initializeVirtualizedList);
Penjelasan:
initializeVirtualizedList
: Fungsi yang mengatur daftar ter-virtualisasi.container
: Kontainer daftar.scrollArea
: Area scroll.content
: Kontainer konten.scrollArea.style.height
: Mengatur tinggi area scroll berdasarkan jumlah item dan tinggi item.handleScroll
: Fungsi yang dipanggil saat event scroll terjadi.scrollTop
: Mendapatkan posisi scroll.containerHeight
: Mendapatkan tinggi kontainer.getVisibleItems
: Menghitung item yang terlihat.renderItems
: Me-render item yang terlihat.addEventListener
: Menambahkan event listener untuk event scroll.handleScroll()
: Panggilan awal untuk me-render item yang terlihat saat daftar pertama kali dimuat.
Kode Lengkap
Berikut adalah kode lengkap untuk daftar ter-virtualisasi:
<!DOCTYPE html>
<html>
<head>
<title>Virtualized List</title>
<style>
.virtualized-list-container {
width: 300px;
height: 400px;
overflow: auto;
position: relative;
border: 1px solid #ccc;
}
.virtualized-list-scroll-area {
width: 100%;
position: relative;
}
.virtualized-list-content {
position: absolute;
top: 0;
left: 0;
width: 100%;
}
.virtualized-list-item {
padding: 10px;
border-bottom: 1px solid #eee;
position: absolute;
width: 100%;
box-sizing: border-box;
}
</style>
</head>
<body>
<div class="virtualized-list-container">
<div class="virtualized-list-scroll-area">
<div class="virtualized-list-content">
<!-- Item will be rendered here -->
</div>
</div>
</div>
<script>
const totalItems = 1000;
const itemHeight = 50;
const items = Array.from({ length: totalItems }, (_, index) => ({
id: index,
text: `Item ${index + 1}`
}));
function getVisibleItems(scrollTop, itemHeight, items, containerHeight) {
const startIndex = Math.max(0, Math.floor(scrollTop / itemHeight));
const endIndex = Math.min(items.length, startIndex + Math.ceil(containerHeight / itemHeight));
return items.slice(startIndex, endIndex);
}
function renderItems(visibleItems, itemHeight, scrollTop) {
const content = document.querySelector('.virtualized-list-content');
content.innerHTML = visibleItems.map(item => `
<div class="virtualized-list-item" style="height: ${itemHeight}px; top: ${item.id * itemHeight}px;">
${item.text}
</div>
`).join('');
}
function initializeVirtualizedList() {
const container = document.querySelector('.virtualized-list-container');
const scrollArea = document.querySelector('.virtualized-list-scroll-area');
const content = document.querySelector('.virtualized-list-content');
scrollArea.style.height = `${totalItems * itemHeight}px`;
function handleScroll() {
const scrollTop = container.scrollTop;
const containerHeight = container.clientHeight;
const visibleItems = getVisibleItems(scrollTop, itemHeight, items, containerHeight);
renderItems(visibleItems, itemHeight, scrollTop);
}
container.addEventListener('scroll', handleScroll);
// Inisialisasi perenderan
handleScroll();
}
document.addEventListener('DOMContentLoaded', initializeVirtualizedList);
</script>
</body>
</html>
Optimasi dan Pertimbangan Tambahan
Meskipun implementasi di atas memberikan dasar untuk daftar ter-virtualisasi, ada beberapa optimasi dan pertimbangan yang dapat Anda tambahkan:
- Buffer: Tambahkan buffer item di atas dan di bawah jendela yang terlihat untuk mencegah artefak perenderan saat scrolling cepat.
- Perkiraan Tinggi: Jika tinggi item bervariasi, gunakan perkiraan tinggi untuk perhitungan awal dan kemudian perbarui setelah item dirender.
- Recycling DOM: Alih-alih me-render dan menghancurkan item DOM, daur ulang yang sudah ada untuk performa yang lebih baik.
- Debouncing atau Throttling: Gunakan debouncing atau throttling pada event scroll untuk mengurangi jumlah panggilan perenderan.
- Lazy Loading: Jika item berisi gambar atau konten lain yang berat, gunakan lazy loading untuk memuatnya hanya saat terlihat.
- Responsif: Pastikan daftar ter-virtualisasi responsif dan berfungsi dengan baik di berbagai ukuran layar.
- Dukungan Aksesibilitas: Terapkan fitur aksesibilitas yang tepat seperti atribut ARIA untuk meningkatkan kegunaan bagi pengguna dengan disabilitas.
Contoh dengan Buffer
Berikut adalah contoh dengan buffer:
function getVisibleItemsWithBuffer(scrollTop, itemHeight, items, containerHeight, bufferSize) {
const startIndex = Math.max(0, Math.floor(scrollTop / itemHeight) - bufferSize);
const endIndex = Math.min(items.length, startIndex + Math.ceil(containerHeight / itemHeight) + 2 * bufferSize);
return items.slice(startIndex, endIndex);
}
Dalam contoh ini, bufferSize
menentukan jumlah item tambahan untuk dirender di atas dan di bawah jendela yang terlihat.
Alternatif dan Pustaka
Jika Anda tidak ingin membuat daftar ter-virtualisasi dari awal, ada beberapa pustaka yang tersedia yang menyediakan fungsionalitas ini:
- react-virtualized: Pustaka populer untuk React.
- react-window: Pustaka lain untuk React yang berfokus pada performa.
- vue-virtual-scroller: Pustaka untuk Vue.js.
- ngx-virtual-scroller: Pustaka untuk Angular.
Pustaka ini menawarkan fitur dan optimasi lanjutan, seperti daur ulang DOM, perkiraan tinggi, dan dukungan untuk layout yang berbeda.
Kesimpulan
Daftar ter-virtualisasi adalah teknik yang ampuh untuk mengoptimalkan performa saat menampilkan data dalam jumlah besar. Dengan hanya me-render item yang terlihat, Anda dapat secara signifikan mengurangi DOM, meningkatkan performa, dan menyediakan pengalaman pengguna yang lebih baik. Baik Anda membuat daftar ter-virtualisasi dari awal atau menggunakan pustaka yang sudah ada, memahami konsep dan teknik yang dibahas dalam panduan ini akan membantu Anda membuat aplikasi web yang efisien dan responsif.
Ingatlah untuk mempertimbangkan persyaratan khusus aplikasi Anda dan memilih pendekatan yang paling sesuai dengan kebutuhan Anda. Eksperimen dengan berbagai optimasi dan parameter untuk mencapai performa terbaik untuk kasus penggunaan Anda.
“`