原生JS實(shí)現(xiàn)虛擬列表(不使用Vue,React等前端框架)
當(dāng)前位置:點(diǎn)晴教程→知識(shí)管理交流
→『 技術(shù)文檔交流 』
1. 什么是虛擬列表虛擬列表(Virtual List)是一種優(yōu)化長(zhǎng)列表渲染性能的技術(shù)。當(dāng)我們需要展示成千上萬(wàn)條數(shù)據(jù)時(shí),如果一次性將所有數(shù)據(jù)渲染到DOM中,會(huì)導(dǎo)致頁(yè)面卡頓甚至崩潰。虛擬列表的核心思想是:只渲染可視區(qū)域內(nèi)的數(shù)據(jù),而不是渲染所有數(shù)據(jù)
2. 使用場(chǎng)景虛擬列表適用于以下場(chǎng)景:
(我覺得實(shí)際場(chǎng)景中,分頁(yè)會(huì)用到更多,用戶要看的數(shù)據(jù),永遠(yuǎn)只是一小部分,就那么幾條,找不到就用搜索 但總要學(xué)學(xué))
3. 虛擬列表原理一句話:
要看了,再渲染
對(duì),就這么簡(jiǎn)單,下面,進(jìn)行分步
這里幾個(gè)難點(diǎn):
4. 實(shí)現(xiàn)虛擬列表Demo.html代碼如下: <!DOCTYPE html> <html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>原生JavaScript虛擬列表實(shí)現(xiàn)</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.list-container {
position: relative;
height: 400px;
overflow: auto;
border: 1px solid #ccc;
margin: 20px auto;
width: 80%;
}
.list-phantom {
position: absolute;
left: 0;
top: 0;
right: 0;
z-index: -1;
}
.list-content {
position: absolute;
left: 0;
right: 0;
top: 0;
overflow: hidden;
}
.list-item {
padding: 10px;
border-bottom: 1px solid #eee;
color: #666;
}
.list-item:hover {
background-color: #f5f5f5;
}
</style>
</head>
<body>
<h1 style="text-align: center; margin: 20px 0;">原生JavaScript虛擬列表</h1>
<div id="virtualList" class="list-container">
<div class="list-phantom"></div>
<div class="list-content"></div>
</div>
<script>
class VirtualList {
constructor(options) {
this.container = options.container;
this.data = options.data || [];
this.itemHeight = options.itemHeight || 50;
this.bufferSize = options.bufferSize || 5;
this.phantom = this.container.querySelector('.list-phantom');
this.content = this.container.querySelector('.list-content');
this.startIndex = 0;
this.endIndex = 0;
this.scrollTop = 0;
this.init();
}
init() {
// 設(shè)置占位容器的高度
this.phantom.style.height = this.data.length * this.itemHeight + 'px';
// 監(jiān)聽滾動(dòng)事件
this.container.addEventListener('scroll', this.handleScroll.bind(this));
// 初始渲染
this.updateVisibleItems();
}
handleScroll() {
// 獲取當(dāng)前滾動(dòng)位置
this.scrollTop = this.container.scrollTop;
// 更新可見項(xiàng)
this.updateVisibleItems();
}
updateVisibleItems() {
// 計(jì)算開始和結(jié)束索引
this.startIndex = Math.floor(this.scrollTop / this.itemHeight);
this.endIndex = this.startIndex + Math.ceil(this.container.clientHeight / this.itemHeight);
// 添加緩沖區(qū)
this.startIndex = Math.max(0, this.startIndex - this.bufferSize);
this.endIndex = Math.min(this.data.length, this.endIndex + this.bufferSize);
// 計(jì)算偏移量
const offsetY = this.startIndex * this.itemHeight;
// 設(shè)置內(nèi)容容器的偏移
this.content.style.transform = `translateY(${offsetY}px)`;
// 渲染可見項(xiàng)
this.renderItems();
}
renderItems() {
// 清空內(nèi)容容器
this.content.innerHTML = '';
// 渲染可見項(xiàng)
for (let i = this.startIndex; i < this.endIndex; i++) {
const item = document.createElement('div');
item.className = 'list-item';
item.innerHTML = this.renderItemContent(this.data[i], i);
item.style.height = this.itemHeight + 'px';
this.content.appendChild(item);
}
}
renderItemContent(item, index) {
return `<div>索引: ${index}, 內(nèi)容: ${item}</div>`;
}
}
// 生成測(cè)試數(shù)據(jù)
const data = Array.from({ length: 10000 }, (_, i) => `列表項(xiàng) ${i + 1}`);
// 初始化虛擬列表
const virtualList = new VirtualList({
container: document.getElementById('virtualList'),
data: data,
itemHeight: 50,
bufferSize: 10
});
</script>
</body>
</html>
5.最后總結(jié)為什么滾動(dòng)到指定位置后會(huì)將對(duì)應(yīng)區(qū)域數(shù)據(jù)渲染? 1.監(jiān)聽滾動(dòng)事件 2.滾動(dòng)觸發(fā)數(shù)據(jù)更新方法 3.根據(jù)滾動(dòng)距離計(jì)算當(dāng)前數(shù)據(jù)索引 4.根據(jù)可視區(qū)域計(jì)算要渲染數(shù)據(jù)項(xiàng) 5.渲染數(shù)據(jù) 6.定位內(nèi)容 轉(zhuǎn)自https://www.cnblogs.com/FatTiger4399/p/18780549 該文章在 2025/3/20 9:22:34 編輯過(guò) |
關(guān)鍵字查詢
相關(guān)文章
正在查詢... |