当前位置: 首页 > news >正文

每天一个前端小知识 Day 33 - 虚拟列表与长列表性能优化实践(Virtual Scroll)

虚拟列表与长列表性能优化实践(Virtual Scroll)


🎯 一、背景:为何需要虚拟列表?

在实际业务中,我们经常需要渲染大量数据项,比如:

  • 聊天记录滚动展示
  • 电商商品长列表
  • 数据中心表格(DataGrid)

如果直接将上千条 DOM 节点一次性渲染,会引起:

问题说明
卡顿/掉帧浏览器 DOM 渲染耗时过大,UI thread 被堵塞
内存暴涨节点数量越多,内存占用越高,GC 压力大
页面响应慢任何交互都有延迟,影响用户体验

🧠 二、什么是虚拟滚动(Virtual Scroll)?

虚拟列表是一种“按需渲染”的技术:

只渲染当前可视区域内的少量 DOM 节点,其余的用空白占位撑起滚动高度,从而模拟完整列表滚动。

通过“视口裁剪 + 滚动同步”,将 10000 项渲染的压力降到几十项以内。


🧩 三、虚拟滚动原理简述

📦 示例:

  • 假设每一项高度为 50px
  • 列表有 10000 项,总高度为 500,000px
  • 实际可视区域只能显示 20 项

👉 只渲染这 20 项 DOM 元素
👉 设置容器滚动高度为总高度
👉 根据滚动位置动态更新“可视区域数据 + offset”


📈 可视区域公式计算:

const visibleCount = Math.ceil(containerHeight / itemHeight);
const startIndex = Math.floor(scrollTop / itemHeight);
const endIndex = startIndex + visibleCount;

🛠 四、手写简易虚拟列表(原生 JS 示例)

<div id="container" style="height:300px; overflow:auto; position:relative;"><div id="phantom"></div><div id="content" style="position:absolute; top:0;"></div>
</div>
const data = Array.from({ length: 10000 }, (_, i) => `Item ${i}`);
const itemHeight = 30;
const container = document.getElementById('container');
const phantom = document.getElementById('phantom');
const content = document.getElementById('content');phantom.style.height = `${data.length * itemHeight}px`;container.addEventListener('scroll', () => {const scrollTop = container.scrollTop;const start = Math.floor(scrollTop / itemHeight);const visibleCount = Math.ceil(container.clientHeight / itemHeight);const end = start + visibleCount;const visibleData = data.slice(start, end);content.style.transform = `translateY(${start * itemHeight}px)`;content.innerHTML = visibleData.map(d => `<div style="height:${itemHeight}px">${d}</div>`).join('');
});

✅ 这样页面只渲染有限 DOM,性能稳定,滚动流畅。


⚙️ 五、常见框架中的虚拟列表解决方案

框架工具/库特点
Reactreact-window, react-virtualized支持列表、表格、无限滚动等
Vuevue-virtual-scroller轻量虚拟滚动组件
通用virtual-scroll, 自研实现可组合封装、按需优化

✅ React 示例(react-window)

import { FixedSizeList as List } from 'react-window';<Listheight={300}itemCount={10000}itemSize={35}width={300}
>{({ index, style }) => <div style={style}>Row {index}</div>}
</List>

💡 六、进阶优化点(加分项)

优化点说明
预加载/缓存策略滚动过程中预先加载上下 10 项,减少空白感
动态高度支持对于不等高元素,使用 IntersectionObserver 动态调整
滚动锚点保持改变列表数据时自动保留原始滚动位置
图片懒加载 + 虚拟滚动组合实现高性能图文流

🧪 七、面试高频问题拆解

📌 Q1:你如何优化一个 1 万条数据的滚动列表渲染?

答:

使用虚拟列表技术,仅渲染可视区域内的 DOM 元素,其余通过容器撑高模拟滚动。可结合 react-window 或 vue-virtual-scroller 来高效实现。还可结合懒加载、IntersectionObserver 等增强体验。

📌 Q2:虚拟列表支持不等高的 item 吗?如何处理?

答:

可以,但较复杂。需要:

  • 使用 ResizeObserverIntersectionObserver 动态记录每项高度
  • 使用映射表缓存高度
  • 更新滚动偏移时进行累加偏移量校正

更推荐高度一致或接近的场景。

📌 Q3:如何避免滚动白屏或闪烁?

答:

  • 设置合理的 buffer 区(上下额外渲染几项)
  • 使用 will-change 预优化 transform
  • DOM diff 使用 key 提升更新效率
  • 避免频繁触发 innerHTML 重排

✅ 总结

能力维度说明
虚拟列表基本原理利用偏移+容器撑高+动态渲染实现
实现方式原生计算/封装组件/react-window/vue-scroller
面试价值性能优化落地实践,体现工程能力
实战场景电商列表、聊天滚动、日志流、表格大数据等
http://www.dtcms.com/a/282001.html

相关文章:

  • 短剧App/小程序/H5多端开发全流程解析:从架构设计到性能优化
  • WPF 加载和显示 GIF 图片的完整指南
  • 借助AI学习开源代码git0.7之编译和使用
  • Gradle vs Maven:构建工具世纪对决 —— 像乐高积木与标准模型之间的选择艺术
  • SQL中对字符串字段模糊查询(LIKE)的索引命中情况
  • Git问题排查与故障解决详解
  • C++---emplace_back与push_back
  • 工业网络协议桥接设计指南:从LIN到CAN/RS-232的毫秒级互通方案
  • Adobe illustrator、klayout绘制光刻图及其尺寸映射
  • docker的搭建
  • 微信小程序141~150
  • 控制Vue对话框显示隐藏
  • 实例操作:基于 PipeLine 实现 JAVA项目集成 SonarQube代码检测通知 Jenkins
  • 【Linux】基本指令详解(二) 输入\输出重定向、一切皆文件、认识管道、man、cp、mv、echo、cat
  • 如何配置一个简单的docker容器应用?
  • 【2025/07/16】GitHub 今日热门项目
  • 基于 Spring Boot 构建的文件摆渡系统(File Ferry System)
  • Python19 —— 一维数据的处理
  • 小白成长之路-Elasticsearch 7.0 配置
  • Coze工作流无法更新问题处理
  • 如何通过扫描电镜检测汽车清洁度中的硬质颗粒并获取成分信息
  • 【源力觉醒 创作者计划】百度携文心 4.5 入局,开源大模型市场再添一员猛将,与 Qwen3 对比如何?
  • C++修炼:IO流
  • WPF 多窗口分文件实现方案
  • openEuler 22.03 LTS Rootless Docker 安装指南
  • 【MySQL基础】MySQL事务详解:原理、特性与实战应用
  • 每日算法刷题Day49:7.16:leetcode 差分5道题,用时2h
  • c语言-数据结构-二叉树的遍历
  • 数字ic后端设计从入门到精通11(含fusion compiler, tcl教学)全定制设计入门
  • arm版本的ubuntu安装git或者vim等方法