前端虚拟列表深度拆解

虚拟列表是为了解决什么问题

真实项目中的痛点:

想象一个后台系统:用户列表:10 万条;订单列表:20 万条;日志列表:百万级;表格里还有:多列、复杂 DOM、hover、操作按钮、状态标签

直接 map 渲染:

data.map(item => <Row key={item.id} />)

会遇到:首次渲染卡死、滚动严重掉帧、内存暴涨和浏览器直接崩

根因只有一个:DOM 太多浏览器不是怕 JS,浏览器最怕的是成千上万个 DOM 节点

总的来说虚拟列表就是只渲染可视区域内的列表项,而其余的用占位高度“假装存在”

虚拟列表的核心思想

我总结主要要理解这四点:
1.可视区域(viewport):屏幕当前能看到的那一段高度

2.列表总高度(total height):假设所有 item 都渲染后的总高度(假的,但要算出来)

3.起始索引和结束索引:根据滚动距离,计算现在应该显示哪几条

4. 偏移量(offset / translateY):让当前渲染的 items 看起来在正确的位置

虚拟列表的本质实现原理

假设每一项高度固定,这个是最简单的,真是项目中大量列表数据一般都是每一项数据都是高度固定的

itemHeight = 50px 容器高度 = 500px

那屏幕最多能显示:500 / 50 = 10 条

通常会多渲染几条(缓冲区):实际渲染 = 10 + 4 = 14 条

根据滚动距离算索引

startIndex = Math.floor(scrollTop / itemHeight) endIndex = startIndex + visibleCount

不渲染所有 DOM,但要让滚动条是对的

<div> <div></div> <!-- 撑开高度 --> <div></div> <!-- 只放可见项 --> </div>
.phantom { height: totalCount * itemHeight; }

偏移当前渲染区域

offsetY = startIndex * itemHeight
.list { transform: translateY(offsetY); }

视觉效果:DOM 只有十几条、滚动条像真的有十万条

真实项目React中使用demo整体代码(可直接使用)

import React, { useRef, useState, useEffect, useMemo,useCallback } from 'react' interface VirtualListProps<T> { data: T[] height: number // 容器高度 itemHeight: number // 每一项高度(固定) renderItem: (item: T, index: number) => React.ReactNode buffer?: number // 缓冲区 } export function VirtualList<T>({ data, height, itemHeight, renderItem, buffer = 5, }: VirtualListProps<T>) { const containerRef = useRef<HTMLDivElement>(null) const [scrollTop, setScrollTop] = useState(0) /** 可视区能显示的条数 */ const visibleCount = Math.ceil(height / itemHeight) /** 开始索引 */ const startIndex = Math.max( Math.floor(scrollTop / itemHeight) - buffer, 0 ) /** 结束索引 */ const endIndex = Math.min( startIndex + visibleCount + buffer * 2, data.length ) /** 当前渲染的数据 */ const visibleData = useMemo( () => data.slice(startIndex, endIndex), [data, startIndex, endIndex] ) /** 偏移量 */ const offsetY = startIndex * itemHeight /** 总高度(关键:撑开滚动条) */ const totalHeight = data.length * itemHeight /** 滚动事件 */ const onScroll = useCallback(() => { if (!containerRef.current) return setScrollTop(containerRef.current.scrollTop) }, []) return ( <div ref={containerRef} style={{ height, overflowY: 'auto', position: 'relative', border: '1px solid #ddd', }} onScroll={onScroll} > {/* 撑开高度 */} <div style={{ height: totalHeight }} /> {/* 实际渲染内容 */} <div style={{ position: 'absolute', top: 0, left: 0, right: 0, transform: `translateY(${offsetY}px)`, }} > {visibleData.map((item, index) => ( <div key={startIndex + index} style={{ height: itemHeight, boxSizing: 'border-box', borderBottom: '1px solid #eee', }} > {renderItem(item, startIndex + index)} </div> ))} </div> </div> ) }

如何使用这个 VirtualList

const data = Array.from({ length: 100000 }, (_, i) => `Row ${i}`) export default function App() { return ( <VirtualList data={data} height={500} itemHeight={50} renderItem={(item) => <div>{item}</div>} /> ) }

针对这个demo,我总结出几个关键点

1.下面这行代码,不显示任何内容,只是为了撑开滚动条

<div style={{ height: totalHeight }} />

2.为什么 content 要 absolute + translateY?因为transform不会出发布局重排,性能比设置top好

transform: translateY(offsetY)

3.buffer 的意义,是防止滚动过快出现白屏,提前渲染上下几条

buffer = 5

4.为什么 key 用startIndex + index因为:同一条数据在不同 scrollTop 下会复用 DOM,key 必须全局唯一

可以优化的地方:可以对scroll进行一个节流处理

用 ref 记录 RAF 状态

const rafIdRef = useRef<number | null>(null)

改变 onScroll函数

const onScroll = useCallback(() => { if (!containerRef.current) return // 如果当前帧已经有任务了,直接 return if (rafIdRef.current !== null) return rafIdRef.current = requestAnimationFrame(() => { setScrollTop(containerRef.current!.scrollTop) rafIdRef.current = null }) }, [])

Read more

全面的System Verilog教程:从基础到高级验证

本文还有配套的精品资源,点击获取 简介:System Verilog是用于系统级验证、芯片设计与验证以及FPGA实现的强大硬件描述语言。它扩展了Verilog的基础特性,支持高级语言结构,如类、接口、任务和函数,优化了验证流程。教程内容涵盖System Verilog的基础概念、结构化编程元素、并发与同步机制、现代验证方法学、UVM验证方法论以及标准库的应用。旨在教授学生掌握System Verilog语法和高级特性,实现高效、可维护的验证代码。 1. System Verilog概述及应用领域 1.1 System Verilog的起源与发展 System Verilog是作为硬件设计和验证领域的重要语言,由Verilog发展而来,随后被进一步扩展以满足现代电子设计自动化的需要。其发展始于20世纪90年代,目的是在原有Verilog HDL的基础上,提供更为强大的设计验证功能。 1.1.1 Verilog与VHDL的区别 虽然Verilog和VHDL都是硬件描述语言(HDL),但它们在语法和使用方法上存在差异。Verilog更接近于C语言,而VHDL的语法结构则更接近

基于深度学习YOLO算法+qwen deepseek大模型的无人机河道巡检系统平台 支持AI对话与文档生成分析

基于深度学习YOLO算法+qwen deepseek大模型的无人机河道巡检系统平台 支持AI对话与文档生成分析

YOLO+DeepSeek河道环境检测系统 项目简介 基于改进YOLO深度学习模型与DeepSeek大语言模型的河道环境智能检测与分析系统。本系统采用先进的计算机视觉技术,结合自然语言处理能力,实现对河道环境中各类目标的高精度检测与智能分析。系统支持单张图片、批量图片、视频文件及实时摄像头等多种输入方式,提供从环境检测到智能建议的完整解决方案,为河道治理、环境保护与水资源管理提供智能化技术支持。 ✨ 核心亮点 • 多场景检测支持:全面覆盖单张图片、图片文件夹、视频文件、实时摄像头四种输入方式 • 改进YOLO模型:基于YOLOv5/v8/v11/v12的优化版本,专注河道环境目标检测 • AI智能分析:集成DeepSeek/Qwen大模型,生成专业的河道环境分析与治理建议 • 实时处理反馈:前端实时展示检测进度与结果,支持实时视频流处理 • 完整技术栈:PyTorch深度学习 + SpringBoot后端 + Vue3前端 + Flask中台的完整架构 • 开箱即用:提供完整源码、预训练模型与详细部署文档,快速上手使用 🌊 检测对象范围 系统可精准识别河道

【VR音游】音符轨道系统开发实录与原理解析(OpenXR手势交互)

【VR音游】音符轨道系统开发实录与原理解析(OpenXR手势交互)

VR音游音符轨道系统开发实录与原理解析 在 VR 音游的开发过程中,音符轨道系统是最核心的交互与可视化部分。本文结合一次完整的开发实录,分享从核心原理与设计到VR内容构建的完整过程,帮助读者快速理解音符轨道系统的实现思路。 文章目录 * VR音游音符轨道系统开发实录与原理解析 * 一、实录结果 * 二、VR内容开发步骤 * 1. 准备音符与交互逻辑 * 2. 创建谱面 * 3. 绘制音轨 * 4. 预制件与音频替换 * 三、原理解析(音符轨道系统) * 1. 音符轨道(Note Track) * 2. 轨迹调节与偏移控制 * 3. 音符触摸激活 * 4. 谱面编辑工具(Editor 功能) * 四、总结与展望 * 1. 成果回顾:从零到一的核心突破 * 2. 技术总结:核心设计理念 * 3. 开发难点与问题反思 * 4. 优化策略与改进方向 * 5.

《机器人实践开发①:Foxglove 开发环境完整搭建指南(含常见坑位) 》

《机器人实践开发①:Foxglove 开发环境完整搭建指南(含常见坑位) 》

导语: 在机器人项目中,调试工具往往比算法本身更耗时间。Foxglove 作为新一代机器人可视化平台,提供了强大的话题订阅、视频显示、3D 展示和日志分析能力。本篇从零开始,手把手带你完成 Foxglove 的环境搭建,包含依赖安装、连接配置以及常见踩坑点。 《机器人实践开发》系列文章索引 《机器人实践开发①:Foxglove 开发环境完整搭建指南(含常见坑位)》 《机器人实践开发②:Foxglove 嵌入式移植 + CMake 集成》 《机器人实践开发③:Foxglove可视化机器人的眼睛-视频》 《机器人实践开发④:Foxglove可视化机器人的耳朵-声音》 《机器人实践开发⑤:Foxglove可视化机器人的3D显示》 《机器人实践开发⑥:Foxglove可视化机器人传感器数据》 《机器人实践开发⑦:Foxglove可视化机器人的日志显示》 《机器人实践开发⑧:Foxglove可视化机器人的地图显示》 《机器人实践开发⑨:Foxglove可视化机器人的MyBag 数据回放》 foxglove 官网 Foxglove 是一个专为机器人团队打造的平台,用于收