前端虚拟列表实现:别再渲染10000个DOM节点了

前端虚拟列表实现:别再渲染10000个DOM节点了

前端虚拟列表实现:别再渲染10000个DOM节点了

毒舌时刻

这代码写得跟网红滤镜似的——仅供参考。

各位前端同行,咱们今天聊聊前端虚拟列表。别告诉我你还在一次性渲染10000个列表项,那感觉就像把10000本书全部摆在桌面上——既占地方又难找。

为什么你需要虚拟列表

最近看到一个项目,一个下拉列表有5000个选项,全部渲染导致页面卡死,我差点当场去世。我就想问:你是在做列表还是在做性能杀手?

反面教材

// 反面教材:一次性渲染所有数据 function BigList({ items }) { return ( <ul style={{ height: '400px', overflow: 'auto' }}> {items.map(item => ( <li key={item.id} style={{ height: '50px' }}> {item.name} </li> ))} </ul> ); } // 使用 <BigList items={Array.from({ length: 10000 }, (_, i) => ({ id: i, name: `Item ${i}` }))} /> // 浏览器:我太难了 

毒舌点评:这代码,我看了都替浏览器着急。渲染10000个DOM节点,你是想让用户的电脑变成暖炉吗?

前端虚拟列表的正确姿势

1. 基础虚拟列表实现

// 正确姿势:基础虚拟列表 import { useState, useRef, useMemo, useCallback } from 'react'; function VirtualList({ items, itemHeight, containerHeight }) { const [scrollTop, setScrollTop] = useState(0); const containerRef = useRef(null); // 计算可见区域 const visibleCount = Math.ceil(containerHeight / itemHeight); const totalHeight = items.length * itemHeight; // 计算起始和结束索引 const startIndex = Math.floor(scrollTop / itemHeight); const endIndex = Math.min(startIndex + visibleCount + 1, items.length); // 获取可见项 const visibleItems = useMemo(() => { return items.slice(startIndex, endIndex); }, [items, startIndex, endIndex]); // 偏移量 const offsetY = startIndex * itemHeight; const handleScroll = useCallback((e) => { setScrollTop(e.target.scrollTop); }, []); return ( <div ref={containerRef} style={{ height: containerHeight, overflow: 'auto' }} onScroll={handleScroll} > <div style={{ height: totalHeight, position: 'relative' }}> <div style={{ transform: `translateY(${offsetY}px)` }}> {visibleItems.map((item, index) => ( <div key={item.id} style={{ height: itemHeight }} className="virtual-list-item" > {item.name} </div> ))} </div> </div> </div> ); } // 使用 function App() { const items = Array.from({ length: 10000 }, (_, i) => ({ id: i, name: `Item ${i}` })); return ( <VirtualList items={items} itemHeight={50} containerHeight={400} /> ); } 

2. 使用react-window

// 正确姿势:使用react-window import { FixedSizeList as List } from 'react-window'; function VirtualList({ items }) { const Row = ({ index, style }) => ( <div style={style} className="list-item"> {items[index].name} </div> ); return ( <List height={400} itemCount={items.length} itemSize={50} > {Row} </List> ); } // 使用 function App() { const items = Array.from({ length: 10000 }, (_, i) => ({ id: i, name: `Item ${i}` })); return <VirtualList items={items} />; } 

3. 使用vue-virtual-scroller

<!-- Vue3中使用vue-virtual-scroller --> <template> <RecycleScroller :items="items" :item-size="50" key-field="id" v-slot="{ item }" > <div> {{ item.name }} </div> </RecycleScroller> </template> <script setup> import { RecycleScroller } from 'vue-virtual-scroller'; import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'; const items = Array.from({ length: 10000 }, (_, i) => ({ id: i, name: `Item ${i}` })); </script> <style> .scroller { height: 400px; } .item { height: 50px; display: flex; align-items: center; padding: 0 20px; } </style> 

毒舌点评:早这么写,你的列表早流畅了。别告诉我你还在渲染10000个DOM节点,那你还是趁早去用分页吧。

实战技巧:虚拟列表指南

1. 虚拟列表原理

  1. 只渲染可见项:只渲染视口内的元素
  2. 计算偏移量:通过transform移动内容
  3. 动态高度支持:预估高度或动态计算

2. 最佳实践

  1. 固定高度:优先使用固定高度,性能好
  2. 缓冲区域:上下多渲染几个item,避免白屏
  3. 滚动优化:使用requestAnimationFrame

最后想说的

虚拟列表不是炫技,是性能优化。别再渲染10000个DOM节点了——虚拟化一下,你的应用会飞起来。

虚拟列表就像图书馆的检索系统,不需要把所有书都摆在桌上,只需要展示你想看的那几本。别做图书搬运工,做图书管理员。

Read more

Python——搭建一个有记忆,可以人工干预转人工,调用搜索工具的机器人

Python——搭建一个有记忆,可以人工干预转人工,调用搜索工具的机器人

Python——搭建一个有记忆,可以人工干预转人工,调用搜索工具的机器人 前言 在看了LangGraph官网:https://github.langchain.ac.cn/langgraph/concepts/why-langgraph/ 的教程之后,也是跟着教程做了一个简单的聊天机器人作为初始的一个计划,为啥学的是python的LangGraph呢?我本身学习的就是JAVA,实习找的也是JAVA的工作,但是JAVA确实太卷了,本人之前没有背过八股文,有幸进入一家外包公司java实习,也参与过项目的开发,但是现在的AI发展的很快,我一开始实习的时候,会以为我可能跟不上,因为这是我的第一段实习,可结果确实有着AI的开发辅助,我就发现,很快就可以上手开发,但是要注意提示词,并且规范好,开发的代码格式等。然后又对大模型应用开发这些感兴趣,于是开始慢慢的学了起来。 前置准备 前置准备分为环境和APIkey的获取,这些就不再进行重复了,都放在前面的文章里面有,大家感兴趣的可以看看就行了,包括.env我们也不再进行重复 环境配置 python3.12(python 3.9+)

无人机身份识别解决方案:开源RemoteID完全指南

无人机身份识别解决方案:开源RemoteID完全指南 【免费下载链接】ArduRemoteIDRemoteID support using OpenDroneID 项目地址: https://gitcode.com/gh_mirrors/ar/ArduRemoteID 开源无人机身份识别是当前航空监管的核心要求,FAA RemoteID合规已成为全球无人机行业的标准化需求。ArduRemoteID项目为无人机爱好者和制造商提供了一套完整的开源解决方案,帮助实现符合FAA和欧盟标准的远程身份识别功能。 🚀 快速部署步骤 ArduRemoteID支持ESP32-S3和ESP32-C3硬件平台,部署过程简单高效: 1. 环境准备:安装Arduino CLI和Python 3环境 2. 代码获取:克隆项目仓库到本地目录 3. 依赖安装:运行安装脚本配置编译环境 4. 固件编译:使用make命令一键编译项目 5. 设备烧录:通过USB接口将固件上传到ESP32设备 🔧 多平台兼容方案 该项目支持多种硬件开发板,包括ESP32官方开发板、Bluemark系列模块

在 NVIDIA DGX Spark部署 Stable Diffusion 3.5 并使用ComfyUI

在 NVIDIA DGX Spark部署 Stable Diffusion 3.5 并使用ComfyUI

📖 前言 随着 NVIDIA Blackwell 架构的问世,DGX Spark (Personal AI Supercomputer) 将桌面级 AI 算力推向了新的巅峰。这台怪兽级设备搭载了 GB200/GB10 级别的 GPU 和 NVIDIA Grace CPU (ARM64),并运行在最新的 CUDA 13 环境下。 然而,“最强硬件"往往伴随着"最难环境”。由于 Grace CPU 采用 ARM (aarch64) 架构,且 CUDA 13 过于前沿,传统的 PyTorch 安装方法极易失败。 本文将手把手教你如何在这台超级计算机上部署 Stable Diffusion