JS 框架 词条目录
前端Wiki/词条/虚拟列表

虚拟列表

定义只渲染可视区域内那几行 DOM、滚动时动态替换的长列表优化技术,让万级数据也不卡

浏览器渲染成本与 DOM 节点数直接相关:一万条数据全部生成 DOM,光创建与布局就要几秒,滚动肯定卡。虚拟列表的思路是只保留视口内可见的那一小撮节点(外加少量缓冲),用绝对定位随着滚动位置换内容——菜单始终只有十几行,但滚动表现像完整列表。

实现要点是三个映射:滚动距离对应起始索引、每项高度计算高度数组、内容区用撑高容器产生真实滚动条。其中不定高是最难的部分:未知高度要先估算并占位,渲染后回测真实高度再修正位置,React 的 react-window 与 vue-virtual-scroller 都内置了这类处理。

JavaScript
// 定高虚拟列表的最小实现:感受滚动的核心机制
var DATA = []; for (var i = 0; i < 100000; i++) DATA.push('第 ' + i + ' 行');
var ITEM_H = 32, VIEW_H = 400, BUFFER = 4;

var viewport = document.createElement('div');
viewport.style.cssText = 'height:' + VIEW_H + 'px;overflow:auto;position:relative';
var total = document.createElement('div');
total.style.height = DATA.length * ITEM_H + 'px';     // 撑出真实滚动条
var content = document.createElement('div');
content.style.cssText = 'position:absolute;left:0;right:0;top:0';
viewport.appendChild(total); viewport.appendChild(content); document.body.appendChild(viewport);

function renderItems() {
  var start = Math.max(0, Math.floor(viewport.scrollTop / ITEM_H) - BUFFER);
  var end = Math.min(DATA.length, Math.ceil((viewport.scrollTop + VIEW_H) / ITEM_H) + BUFFER);
  content.style.top = start * ITEM_H + 'px';
  content.innerHTML = '';
  for (var i = start; i < end; i++) {
    var row = document.createElement('div');
    row.style.cssText = 'height:' + ITEM_H + 'px;line-height:' + ITEM_H + 'px;padding:0 12px;border-bottom:1px solid #eee';
    row.textContent = DATA[i];
    content.appendChild(row);      // 始终只渲染约 VIEW_H/ITEM_H + 2*BUFFER 行
  }
}
viewport.addEventListener('scroll', renderItems);
renderItems();
⚠ 常见误区
🔗 相关词条VueReact
← 返回来源章节Vue