前端虚拟列表实现:别再渲染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

web前端开发岗位就业前景和未来变化分析(附:AI技术如何进一步影响前端工作)

web前端开发岗位就业前景和未来变化分析(附:AI技术如何进一步影响前端工作)

web前端开发岗位就业前景和未来变化分析,被AI取代的风险评估 Qwen3-Max 以下是对 Web 前端开发岗位的就业前景、未来变化趋势及被 AI 取代风险 的系统性分析,结合 2025 年最新行业动态、技术演进与劳动力市场数据: 一、当前就业市场现状(2025年) ✅ 趋势特征: * 初级岗位大幅萎缩: 据 LinkedIn 与 Indeed 数据,2021–2024 年,全球“前端工程师”招聘需求下降 60%~70%,尤以基础切图、表单开发类岗位为主。 * 中高级岗位结构性分化: * 纯 UI 实现岗减少; * 工程化、架构、跨端、AI 协同类岗位需求上升(如“前端架构师”“Web 全栈 AI 工程师”)。 * 薪资两极化:

ComfyUI v0.18.0 发布:显存与内存极限优化、VAE架构全面进化、API节点与前端生态深度升级

一、版本概览:一次“以稳定性与性能为核心”的里程碑更新 ComfyUI v0.18.0 于 2026 年 3 月 21 日 正式发布,这是一个不可变版本(仅允许修改发布标题与说明),也是目前为止变更密度最高、底层改动最深的一次版本更新之一。 本次更新共计: * 53 次提交 * 79 个文件变更 * 22 位贡献者 * 覆盖 核心推理、VAE、显存管理、训练、API 节点、前端、工作流模板、CLI 参数、跨平台支持 整体方向可以总结为四个关键词: 更省显存 · 更稳内存 · 更强扩展 · 更一致的数据类型体系 二、显存与内存管理:v0.18.0

Android WebRTC 屏幕共享实战:低延迟传输与权限管理最佳实践

快速体验 在开始今天关于 Android WebRTC 屏幕共享实战:低延迟传输与权限管理最佳实践 的探讨之前,我想先分享一个最近让我觉得很有意思的全栈技术挑战。 我们常说 AI 是未来,但作为开发者,如何将大模型(LLM)真正落地为一个低延迟、可交互的实时系统,而不仅仅是调个 API? 这里有一个非常硬核的动手实验:基于火山引擎豆包大模型,从零搭建一个实时语音通话应用。它不是简单的问答,而是需要你亲手打通 ASR(语音识别)→ LLM(大脑思考)→ TTS(语音合成)的完整 WebSocket 链路。对于想要掌握 AI 原生应用架构的同学来说,这是个绝佳的练手项目。 从0到1构建生产级别应用,脱离Demo,点击打开 从0打造个人豆包实时通话AI动手实验 Android WebRTC 屏幕共享实战:低延迟传输与权限管理最佳实践 背景痛点分析 在Android端实现WebRTC屏幕共享时,开发者通常会遇到以下几个典型问题: 1. 跨版本兼容性问题:从Android

双剑破天门:攻防世界Web题解之独孤九剑心法(七)

双剑破天门:攻防世界Web题解之独孤九剑心法(七)

免责声明:用户因使用公众号内容而产生的任何行为和后果,由用户自行承担责任。本公众号不承担因用户误解、不当使用等导致的法律责任 **本文以攻防世界部分题为例进行演示,后续会对攻防世界大部分的web题目进行演示,如果你感兴趣请关注** 目录 一:Newscenter 二:upload1 三:Xff_referer 四:Command_execution 五:总结 1. Newscenter(SQL注入) 2. upload1(文件上传漏洞) 3. Xff_referer(HTTP头伪造) 4. Command_execution(命令注入) 一:Newscenter 打开为如下所示 经过尝试,得知在输入框中输入数字可得到不同内容 输入23就没有新闻 所以我们得知这个输入框和数据库有交互,那这题考察的可能就是SQL注入 发现将数据库中所有的内容都查询了出来,那这个题考察的就是SQL注入 字段长度为3 23' order by