Q27 · React / Vue 优化
虚拟列表是如何实现的?什么场景下使用?
⚡ 速记答案(30 秒)
- 原理:只渲染可视区域内的元素,通过计算滚动位置动态替换内容
- 核心:固定容器高度 + 绝对定位 + 计算可见元素范围 + 动态渲染
- 场景:长列表(>100 项)、无限滚动、数据表格
- 库:react-window、react-virtualized、vue-virtual-scroller
📖 详细讲解
虚拟列表原理
核心思想
+-------------------+
| 占位区域 | ← 上方不可见区域(padding-top)
+-------------------+
| 可见项 1 |
| 可见项 2 | ← 实际渲染(10-20 个)
| 可见项 3 |
+-------------------+
| 占位区域 | ← 下方不可见区域(padding-bottom)
+-------------------+实现步骤
1. 容器设置固定高度和 overflow: auto
2. 监听滚动事件
3. 计算当前可见范围
4. 只渲染可见范围内的元素
5. 使用 padding 或 transform 撑开滚动区域
性能对比
| 方案 | 1000 项渲染时间 | 内存占用 |
|---|---|---|
| 普通列表 | ~200ms | 高 |
| 虚拟列表 | ~10ms | 低 |
使用场景
• 消息列表(聊天)
• 数据表格
• 订单列表
• 日志展示
💻 代码示例
简易虚拟列表实现
import { useState, useRef, useEffect, useMemo } from 'react';
interface VirtualListProps<T> {
items: T[];
itemHeight: number;
containerHeight: number;
renderItem: (item: T, index: number) => React.ReactNode;
}
function VirtualList<T>({ items, itemHeight, containerHeight, renderItem }: VirtualListProps<T>) {
const [scrollTop, setScrollTop] = useState(0);
const containerRef = useRef<HTMLDivElement>(null);
const { startIndex, endIndex, visibleItems, paddingTop, paddingBottom } = useMemo(() => {
const totalHeight = items.length * itemHeight;
const startIndex = Math.floor(scrollTop / itemHeight);
const visibleCount = Math.ceil(containerHeight / itemHeight);
const endIndex = Math.min(startIndex + visibleCount + 1, items.length);
return {
startIndex,
endIndex,
visibleItems: items.slice(startIndex, endIndex),
paddingTop: startIndex * itemHeight,
paddingBottom: (items.length - endIndex) * itemHeight,
};
}, [items, itemHeight, containerHeight, scrollTop]);
const handleScroll = (e: React.UIEvent<HTMLDivElement>) => {
setScrollTop(e.currentTarget.scrollTop);
};
return (
<div
ref={containerRef}
style={{ height: containerHeight, overflow: 'auto' }}
onScroll={handleScroll}
>
<div style={{ paddingTop, paddingBottom }}>
{visibleItems.map((item, i) => (
<div key={startIndex + i} style={{ height: itemHeight }}>
{renderItem(item, startIndex + i)}
</div>
))}
</div>
</div>
);
}面试技巧:回答性能问题时,先说指标和标准,再讲优化手段,最后结合实际项目经验。