跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaScript大前端算法

前端虚拟列表实现:避免一次性渲染大量 DOM 节点

综述由AI生成探讨前端虚拟列表的实现原理与应用。针对一次性渲染大量 DOM 节点导致的页面卡顿问题,介绍了基础虚拟列表方案及 react-window、vue-virtual-scroller 等成熟库的使用。核心策略包括只渲染可见区域元素、计算偏移量动态定位以及利用固定高度提升性能。通过对比反面教材与最佳实践,帮助开发者优化长列表性能,提升用户体验。

ServerBase发布于 2026/4/5更新于 2026/5/2429 浏览
前端虚拟列表实现:避免一次性渲染大量 DOM 节点

前端虚拟列表实现:避免一次性渲染大量 DOM 节点

背景与问题

前端开发中,处理长列表数据时若一次性渲染所有项(如 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>

核心原理与最佳实践

1. 虚拟列表原理
  1. 只渲染可见项:仅渲染视口内的元素,减少 DOM 数量。
  2. 计算偏移量:通过 CSS transform 移动内容位置。
  3. 动态高度支持:预估高度或动态计算以适应不同内容。
2. 最佳实践
  1. 固定高度:优先使用固定高度,性能表现更好。
  2. 缓冲区域:上下多渲染几个 item,避免滚动时的白屏现象。
  3. 滚动优化:结合 requestAnimationFrame 优化滚动事件处理。

总结

虚拟列表是性能优化的重要手段,而非炫技。通过虚拟化技术,应用无需渲染所有数据即可流畅展示。建议根据项目需求选择合适的库或自行实现,以提升用户体验。

目录

  1. 前端虚拟列表实现:避免一次性渲染大量 DOM 节点
  2. 背景与问题
  3. 反面教材
  4. 实现方案
  5. 1. 基础虚拟列表实现
  6. 2. 使用 react-window
  7. 3. 使用 vue-virtual-scroller
  8. 核心原理与最佳实践
  9. 1. 虚拟列表原理
  10. 2. 最佳实践
  11. 总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • OpenClaw 多 Agent 架构与飞书机器人对接实战
  • OpenClaw.ai:Agentic AI 时代的 Spring Framework 时刻
  • Redis 7 持久化机制详解:RDB 与 AOF
  • LLM 推理与训练 GPU 显存估算方法详解
  • 网络安全细分岗位解析与学习路径指南
  • Adaptive-Note RAG 框架解析:迭代信息搜集与自适应记忆审核
  • AI 幻觉详解:大模型为何会一本正经地胡说八道?
  • 攻防世界 Web 安全挑战题解与代码审计实战
  • 用 AI 打造鸿蒙游戏 NPC 的开发体验与思考
  • 2026 年 3 月全球 AI 前沿动态
  • Linux 部署 OpenClaw 并接入 QQ 机器人
  • Unity 编辑器扩展开发指南
  • OpenClaw 网络搜索与抓取工具最佳实践指南
  • Neo4j 数据库运行时连接失败解决方案
  • LLM4Rec 在业界的应用范式梳理
  • Codex 接入 Kimi K2/GLM-4.6 环境配置指南 (Windows/macOS/Ubuntu)
  • BaseCTF Week3 Web 与杂项解题思路
  • Python 副业接单渠道与学习路径规划
  • AI 驱动接口测试全流程自动化实战
  • Python 零基础系统学习指南与核心技能图谱

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online