前端性能优化之虚拟滚动(Virtual Scrolling)详解与总结
一、什么是虚拟滚动?
✅ 定义:
虚拟滚动(Virtual Scrolling) 是一种前端性能优化技术,用于在渲染大量列表数据时,只渲染可视区域内的元素,而不是一次性渲染全部数据。
核心思想:
“只渲染用户能看到的那部分”
二、为什么需要虚拟滚动?
当面对以下场景时,页面会出现明显的卡顿或内存占用过高问题:
- 渲染上万条数据的列表
- 列表项结构复杂(如包含图片、动画等)
- 移动端设备性能有限
- 需要实时更新的长列表(如聊天记录、日志)
性能瓶颈分析:
问题 |
影响 |
DOM 节点过多 |
页面卡顿、滚动不流畅 |
内存占用高 |
导致浏览器崩溃 |
首屏加载慢 |
用户体验差 |
三、虚拟滚动的工作原理
核心机制:
- 计算可视区域高度
- 获取可视区域索引范围
- 动态渲染可视区域的 DOM 元素
- 通过 scrollTop 控制偏移量实现滚动效果
关键公式:
const visibleCount = Math.ceil(containerHeight / itemHeight);
const startIndex = Math.floor(scrollTop / itemHeight);
const endIndex = startIndex + visibleCount;
滚动监听优化:
使用 requestAnimationFrame
或 IntersectionObserver
替代原生 scroll
监听,提升性能。
四、虚拟滚动的核心实现步骤
1. 计算容器尺寸
const containerHeight = container.clientHeight;
const itemHeight = 50;
2. 渲染可视区域内容
function renderVisibleItems(scrollTop) {
const startIndex = Math.floor(scrollTop / itemHeight);
const endIndex = startIndex + visibleCount;
const visibleItems = data.slice(startIndex, endIndex);
list.innerHTML = '';
visibleItems.forEach((item, index) => {
const div = document.createElement('div');
div.style.position = 'absolute';
div.style.top = `${startIndex * itemHeight}px`;
div.style.height = `${itemHeight}px`;
div.textContent = item.text;
list.appendChild(div);
});
}
3. 设置占位高度
为了让滚动条正常显示,需设置一个“占位元素”表示整个列表的高度:
<div id="placeholder" style="height: calc(10000 * 50px)">div>
五、虚拟滚动的类型(按方向)
类型 |
描述 |
场景举例 |
垂直虚拟滚动 |
只渲染垂直方向上的可见元素 |
列表、聊天记录、日志展示 |
水平虚拟滚动 |
只渲染水平方向上的可见元素 |
表格横向滚动、时间轴展示 |
二维虚拟滚动 |
同时对行和列进行虚拟化 |
大型表格、电子表格、矩阵数据展示 |
六、虚拟滚动的优缺点对比
优点 |
缺点 |
✅ 显著减少 DOM 数量 |
❌ 实现复杂度较高 |
✅ 提升渲染性能 |
❌ 不适合所有场景(如数据量小) |
✅ 减少内存占用 |
❌ 需要手动处理布局逻辑 |
✅ 支持大数据量渲染 |
❌ SEO 不友好(纯 JS 渲染) |
七、常见开源虚拟滚动库推荐
库名 |
特点 |
GitHub 地址 |
react-window |
React 专用,轻量高效 |
https://github.com/bvaughn/react-window |
react-virtualized |
功能丰富但体积较大 |
https://github.com/bvaughn/react-virtualized |
vue-virtual-scroll-list |
Vue 专用虚拟滚动组件 |
https://github.com/Ayoue/vue-virtual-scroll-list |
ngx-ui-scroll |
Angular 专用虚拟滚动 |
https://github.com/ValueForward/ngx-ui-scroll |
Svelte-Virtual-List |
Svelte 专用虚拟滚动组件 |
https://github.com/roope-kar/svelte-virtual-list |
八、虚拟滚动的应用场景总结(10 大案例)
编号 |
应用场景 |
描述 |
1 |
聊天记录列表 |
千级消息滚动流畅 |
2 |
日志系统 |
展示数万条服务器日志 |
3 |
数据看板 |
展示大量图表数据 |
4 |
文件管理器 |
显示成千上万个文件 |
5 |
电商商品列表 |
支持无限滚动的商品展示 |
6 |
通讯录 |
展示数千个联系人 |
7 |
时间线组件 |
横向时间轴展示 |
8 |
表格组件 |
支持大型 Excel 表格 |
9 |
搜索建议列表 |
防止搜索框卡顿 |
10 |
游戏排行榜 |
动态加载玩家排名 |
九、虚拟滚动的面试题总结(10 大高频)
编号 |
面试题 |
简要答案 |
1 |
什么是虚拟滚动? |
只渲染可视区域内的元素,以提高性能 |
2 |
虚拟滚动适用于哪些场景? |
大数据量、DOM 节点多、移动端性能受限 |
3 |
如何实现虚拟滚动? |
计算可视区域、动态渲染、设置占位高度 |
4 |
虚拟滚动的优缺点是什么? |
减少 DOM、节省内存 vs 实现复杂、SEO 不友好 |
5 |
如何监听滚动事件优化性能? |
使用 requestAnimationFrame 或 IntersectionObserver |
6 |
如何处理变高的列表项? |
预估平均高度 + 动态调整 offset |
7 |
如何支持水平滚动? |
计算可视宽度 + left 偏移 |
8 |
如何实现双向虚拟滚动? |
对行列都进行虚拟化,如大型表格 |
9 |
虚拟滚动如何做 SEO 优化? |
配合服务端渲染(SSR)或静态生成(SSG) |
10 |
常见的虚拟滚动库有哪些? |
react-window、react-virtualized、vue-virtual-scroll-list 等 |
十、设计模式与实现技巧
设计模式 |
应用场景 |
观察者模式 |
监听滚动事件并触发重新渲染 |
策略模式 |
支持不同方向(垂直/水平)的虚拟化策略 |
工厂模式 |
封装创建虚拟滚动实例的逻辑 |
享元模式 |
复用 DOM 节点,避免频繁创建销毁 |
✅ 总结一句话:
虚拟滚动是前端性能优化中应对大数据量渲染的重要手段,它通过“只渲染可见区域”的方式显著降低 DOM 负载,广泛应用于聊天、日志、表格、搜索建议等场景。掌握其原理与实现,是中高级前端工程师必须具备的能力之一。
在 Vue 和 React 中集成虚拟滚动组件,可以显著提升大数据量下的渲染性能。下面我将分别介绍 Vue2/Vue3 与 React 中如何使用主流的虚拟滚动库,并提供完整的代码示例供大家学习参考。
十一、在 Vue 中集成虚拟滚动组件
✅ Vue2 示例:使用 vue-virtual-scroll-list
安装:
npm install vue-virtual-scroll-list
使用示例:
<template>
<virtual-list
:data-key="'id'"
:data-sources="items"
:item-size="50"
:remain="8"
item-tag="div"
>
<template v-slot="{ source }">
<div>{{ source.text }}div>
template>
virtual-list>
template>
<script>
import VirtualList from 'vue-virtual-scroll-list'
export default {
components: { VirtualList },
data() {
return {
items: Array.from({ length: 10000 }, (_, i) => ({
id: i,
text: `Item ${i}`
}))
}
}
}
script>
✅ Vue3 示例:使用 @viselect/vue-virtual-scroller
安装:
npm install @viselect/vue-virtual-scroller
使用示例:
<template>
<RecycleScroller
class="scroller"
:items="items"
:item-size="50"
key-field="id"
v-slot="{ item }"
>
<div class="item">{{ item.text }}div>
RecycleScroller>
template>
<script setup>
import { RecycleScroller } from '@viselect/vue-virtual-scroller'
import '@viselect/vue-virtual-scroller/dist/vue-virtual-scroller.css'
const items = Array.from({ length: 10000 }, (_, i) => ({
id: i,
text: `Item ${i}`
}))
script>
<style scoped>
.scroller {
height: 500px;
}
.item {
height: 50px;
display: flex;
align-items: center;
border-bottom: 1px solid #eee;
}
style>
十二、在 React 中集成虚拟滚动组件
✅ React 示例:使用 react-window
安装:
npm install react-window
使用示例:
import React from 'react'
import { FixedSizeList as List } from 'react-window'
const Row = ({ index, style }) => (
<div style={style}>Item {index}</div>
)
function VirtualizedList() {
return (
<List
height={500}
itemCount={10000}
itemSize={50}
width="100%"
>
{Row}
</List>
)
}
export default VirtualizedList
✅ React + Ant Design Pro 示例:使用 @ant-design/pro-table
虚拟化表格
安装:
npm install antd @ant-design/pro-table
使用示例:
import React from 'react'
import { ProTable } from '@ant-design/pro-components'
const columns = [
{ title: 'ID', dataIndex: 'id' },
{ title: '名称', dataIndex: 'name' },
]
const dataSource = Array.from({ length: 10000 }, (_, i) => ({
id: i,
name: `用户 ${i}`
}))
export default function VirtualizedTable() {
return (
<ProTable
columns={columns}
dataSource={dataSource}
pagination={false}
scroll={{ y: 500 }}
virtual
rowKey="id"
/>
)
}
十三、虚拟滚动常见配置项说明(以 react-window
为例)
配置项 |
类型 |
描述 |
height |
number |
可视区域高度 |
width |
number / string |
容器宽度(支持百分比) |
itemCount |
number |
列表总条数 |
itemSize |
number |
每个列表项的高度 |
direction |
string |
滚动方向(ltr/rtl) |
overscanCount |
number |
渲染额外的上下元素数量(用于平滑滚动) |
十四、虚拟滚动组件设计建议
建议 |
说明 |
✅ 动态高度处理 |
如果 item 高度不一致,建议预估平均高度并动态计算 offset |
✅ 支持水平虚拟滚动 |
使用 FixedSizeGrid 或 VariableSizeGrid 实现二维虚拟滚动 |
✅ 防止频繁重绘 |
使用 React.memo / v-once 等方式减少重复渲染 |
✅ SEO 优化 |
结合 SSR 或静态生成(SSG),避免纯 JS 渲染导致 SEO 不友好 |
✅ 懒加载图片 |
在虚拟滚动中使用 ![]() 提升性能 |
十五、总结对比表
框架 |
推荐库 |
是否支持变高 |
是否支持横向滚动 |
是否支持双向虚拟化 |
Vue2 |
vue-virtual-scroll-list |
✅ |
✅ |
❌ |
Vue3 |
@viselect/vue-virtual-scroller |
✅ |
✅ |
✅ |
React |
react-window |
✅ |
✅ |
✅ |
React |
react-virtualized |
✅ |
✅ |
✅ |
React + AntD |
pro-table |
✅ |
✅ |
✅ |
✅ 总结一句话:
在 Vue 和 React 中集成虚拟滚动组件是优化大数据量渲染性能的关键手段,推荐使用官方维护成熟的开源库(如 react-window
、@viselect/vue-virtual-scroller
),合理配置可实现流畅的用户体验和高效的 DOM 渲染。