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

海尔智能家居集成:从零开始的全屋智能控制方案

海尔智能家居集成:从零开始的全屋智能控制方案 【免费下载链接】haier 项目地址: https://gitcode.com/gh_mirrors/ha/haier 海尔智能家居集成是HomeAssistant生态中最强大的海尔设备连接解决方案,能够将您的海尔智家设备无缝接入智能家居系统。通过这个集成插件,您可以统一管理空调、热水器、窗帘、开关等各类海尔智能产品,实现真正的全屋智能控制。 🎯 您的智能家居需求分析 在开始配置之前,先了解您的具体需求: 家庭环境控制需求 🏠 * 夏季空调自动调节温度 * 冬季热水器智能预热 * 窗帘自动开合管理 设备管理需求 📱 * 统一控制界面 * 实时状态监控 * 远程设备操作 🚀 三步快速上手指南 第一步:选择适合您的安装方式 HACS一键安装(推荐) ⭐ 如果您已经安装了HACS,这是最简单快捷的方式: 1. 打开HACS界面 2. 搜索"haier" 3. 点击安装按钮 手动安装方案 🔧 适合熟悉HomeAssistant基础操作的用户: 1.

智能体来了—初级工作流:数据与接口基础(AI Agent / 低代码必修课)

智能体来了—初级工作流:数据与接口基础(AI Agent / 低代码必修课)

在 AI Agent 和低代码开发盛行的今天,很多同学会画流程图,但一到具体配置参数、处理 API 返回数据时就频频报错。 其实,工作流的本质只有一句话: 数据在不同节点之间的流转与变形。 如果不理解基础的数据类型和接口规范,你的工作流就像堵塞的水管,要么跑不通,要么跑得很慢。 今天,我们通过一张思维导图,系统性地补齐这块短板,帮你真正理解工作流的“底层逻辑”。 一、工作流基础:认识你的“积木” 工作流是由一个个**节点(Node)**串联而成的。在开始搭建之前,我们需要先搞清楚: 自己手里到底有哪些“积木”可以用。 1.1 核心节点类型 在大多数 AI / 低代码平台中,节点可以概括为以下五大类: * 正常节点 执行单一任务,例如发送 HTTP 请求、调用模型、处理数据。 * 传入 / 传出节点

入职 Web3 运维日记 · 第 14 日:铸造无形钥匙 —— OIDC 与 CI/CD 施工实录

时间:入职第 14 天,上午 10:00 天气:多云,代码审查室里的气氛有些焦灼 事件:发现开发团队使用个人电脑直连主网部署合约,并深度剖析 Web3 的“草台班子”现状 上午 10 点,智能合约开发组长在 Slack 核心群里发了一条消息:“新版 Vault (资金库) 合约本地测试完毕,10 分钟后我准备把它发到主网 (Mainnet)。” 作为一个 Web2 摸爬滚打出来的老运维,我对“发主网(生产环境)”这三个字有着天然的敬畏。我立刻端着咖啡走到他工位旁,随口问了一句:“咱们发主网的流程是啥?你用的哪个平台的流水线?” 组长头也没抬,切到了他的 VS Code 终端:“流水线?不用那么麻烦。我在我的 Mac

【PZ-VU9P & PZ-VU13P】璞致FPGA开发板:Xilinx Virtex UltraScale Plus核心板与开发板深度解析

1. 璞致FPGA开发板与Xilinx Virtex UltraScale Plus架构解析 第一次拿到璞致PZ-VU9P开发板时,就被它沉甸甸的金属散热片震撼到了。这可不是普通的FPGA开发板,而是搭载Xilinx旗舰级Virtex UltraScale Plus芯片的"性能怪兽"。先说说这个16nm工艺的Virtex UltraScale Plus架构,它就像是FPGA界的"超级跑车引擎"——在计算密集型应用中,既能飙出26Gbps的GTY收发器速度,又能通过3D-on-3D芯片堆叠技术实现惊人的能效比。 实测在图像处理项目中,VU13P的378万个逻辑单元可以同时处理4路8K视频流,而功耗仅为上代产品的70%。这种性能突破主要来自三大黑科技: * UltraRAM:片上集成432Mb超大容量存储,相当于给数据修了条"高速公路匝道",避免频繁访问外部DDR造成的拥堵 * CLB架构升级:每个可配置逻辑块(CLB)包含8个查找表+16个触发器,布线资源增加40%,我在做波束成形算法时实测布线成功率提升明显 * DSP48E2切片:支持27x18乘法运算和48位累加,做矩阵