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

AIGC已经不是未来,而是现在:2025年最值得关注的6大趋势!

AIGC已经不是未来,而是现在:2025年最值得关注的6大趋势!

过去一年,AIGC(AI 生成内容)从“概念”彻底走向“落地”。无论你是程序员、产品经理、内容创作者,甚至是业余爱好者,AIGC 已经渗透到每一个内容生产链条中,以一种“你还没准备好,它已经来了”的节奏迅速发展。 本文将带你系统了解:2025 年最热门的 AIGC 内容形态、前沿产品、典型用例,以及未来趋势。 🎥 1. 文生视频已落地:Sora 等产品引爆创意革命         当 OpenAI 推出 Sora 时,整个 AI 圈都沸腾了。         只需一句提示词,比如: "一个穿太空服的熊猫在月球上弹钢琴"         Sora 就能输出秒级电影级视频片段。光影、动作、镜头感,全部一应俱全。 🔧 技术关键词:

机器人导论 第六章 动力学(1)——牛顿欧拉法推导与详述

机器人导论 第六章 动力学(1)——牛顿欧拉法推导与详述

机器人动力学分析复习速通 机器人分析分为 牛顿欧拉法、拉格朗日法、高斯法、凯恩方法 matlab提供的逆动力学采用的是牛顿欧拉法:RNE——Recursive Newton-Euler 需要三个参数,第一个是给定最终的角度,第二个是速度,第三个是角加速度,返回各个关节所需要的力矩。 可选参数有重力加速度和负载fext 牛顿欧拉法 我们的目标是给定机器人的关节位置 q、速度 qd 和加速度 qdd,计算出为了产生这个运动状态,每个关节需要施加多大的驱动力矩 。 一上来看到有人问——我们不是用力域雅可比解决了每个关节应该分配多大力矩的问题了吗? 这是我初学的时候也弄混的问题。 “力域雅可比”解决的是一个不同的问题,属于静力学或外力映射范畴,他的目的是将作用在机器人末端执行器上的外力/力矩 映射到对应的关节空间力矩 。 区别就是一个是给定运动状态,计算每个关节为了达到这个运动状态需要多大力; 另一个则是给定末端的力,计算这个力分配在各个关节上是多大。 牛顿欧拉法的精髓在于正推和逆推,我们来看这个过程: * 正向递推(Forward Recursion):从基

Qwen3论文阅读

1、核心架构改进: 1)注意力机制: 采用了 GQA (Grouped Query Attention) 以提高推理效率 什么是GQA注意力机制? 介于传统的多头注意力机制以及极简的MQA注意力机制之间,目标为平衡生成速度以及模型精度 首先我们先看一看多头注意力机制以及多询注意力机制的区别 MHA (Multi-Head Attention): 每个 Query (Q) 都有对应的 Key (K) 和 Value (V)。虽然效果最好,但在推理时需要缓存大量的 KV 状态(KV Cache),导致内存占用高,推理速度慢。 MQA (Multi-Query Attention): 所有的 Q 共享同一组 K 和 V。这极大地减少了内存占用和数据传输,速度极快,但由于表达能力大幅下降,模型性能(准确度)通常会受损。 GQA:

Docker 安装 Neo4j 保姆级教程

Docker 安装 Neo4j 保姆级教程 本教程适用于零基础用户,详细讲解如何在 Windows 或 Linux 环境下通过 Docker 安装并配置 Neo4j 图数据库。 Neo4j 官方 Docker 文档 1. 环境准备 * 已安装 Docker(Docker Desktop 官网) * Linux 和 Windows 均可 2. 创建挂载目录 在宿主机上新建以下目录,用于数据持久化和配置挂载(以 Linux 为例,Windows 可用资源管理器新建文件夹): mkdir -p /home/neo4j/data /home/neo4j/logs /home/neo4j/conf /home/