前端怎么用惰性求值优化大数据列表渲染?

司徒成娟 阅读 16

我有个页面要展示上万条数据的列表,直接渲染卡得不行。听说可以用惰性求值只处理可视区域的数据,但不知道具体咋实现。试过用 Array.prototype.slice 截取一部分,但滚动时还是卡顿明显。

有没有人用 Intersection Observer 或虚拟滚动做过类似优化?能给个简单的代码示例吗?比如只在用户滚动到某块区域时才真正生成 DOM 元素。

const data = Array.from({ length: 10000 }, (_, i) => <code>Item ${i}</code>);
// 想在这里实现惰性求值,只渲染可视区域的项
function renderVisibleItems() {
  // ???
}
我来解答 赞 3 收藏
二维码
手机扫码查看
1 条解答
宇航~
宇航~ Lv1
直接用这个思路:别管惰性求值那套术语,前端渲染卡顿主要是 DOM 节点太多,你得做虚拟滚动——只渲染当前可见区域的元素,其他用占位高度撑开列表高度。

核心就三步:
1. 用一个固定高度的容器包住列表,设置 overflow: auto
2. 计算当前滚动位置对应的可见区域索引范围
3. 只渲染这部分 DOM,其他用空 div 占位(高度要精确)

下面是个能跑的最小示例,不依赖 IntersectionObserver,纯靠 scroll 事件和 offsetHeight 计算,性能更稳:

<div id="list-container" style="height: 400px; overflow: auto; border: 1px solid #ccc;">
<div id="list-inner"></div>
</div>

<script>
const ITEM_HEIGHT = 40; // 每项高度,必须固定!
const data = Array.from({ length: 10000 }, (_, i) => Item ${i});

const container = document.getElementById('list-container');
const inner = document.getElementById('list-inner');

// 先设总高度,让滚动条能滚动
inner.style.height = ${data.length * ITEM_HEIGHT}px;

// 滚动时只渲染可视区域
container.addEventListener('scroll', () => {
const scrollTop = container.scrollTop;
const startIndex = Math.floor(scrollTop / ITEM_HEIGHT);
const visibleCount = Math.ceil(container.clientHeight / ITEM_HEIGHT) + 2; // 多留2个防白屏
const endIndex = Math.min(startIndex + visibleCount, data.length);

// 清空旧节点
inner.innerHTML = '';

// 计算当前渲染项的起始偏移
const offsetTop = startIndex * ITEM_HEIGHT;

// 创建占位 div + 真实节点
const placeholder = document.createElement('div');
placeholder.style.height = ${offsetTop}px;
inner.appendChild(placeholder);

const fragment = document.createDocumentFragment();
for (let i = startIndex; i < endIndex; i++) {
const el = document.createElement('div');
el.style.height = ${ITEM_HEIGHT}px;
el.textContent = data[i];
el.style.borderBottom = '1px solid #eee';
fragment.appendChild(el);
}
inner.appendChild(fragment);
});

// 初始化先渲染一次
container.dispatchEvent(new Event('scroll'));
</script>


注意:
- ITEM_HEIGHT 必须固定,否则偏移量算不准
- 滚动事件里别做重计算,这个 demo 是最轻量的
- 真项目里建议用 React/Vue 的虚拟列表库(比如 react-window),自己手写容易踩坑(比如滚动回弹、焦点错乱)

别试 IntersectionObserver 做列表渲染,它更适合“懒加载图片”这种场景,列表滚动太频繁,observer 回调延迟会更卡。
点赞 1
2026-02-27 18:23