数据懒加载和虚拟列表

“数据懒加载”“虚拟列表(Virtual List / Virtual Scrolling)” 看起来都与“滚动”和“性能优化”有关,但其实它们解决的是不同的问题
我来帮你系统讲清楚两者的区别、联系,以及它们可以怎样配合使用。


🧩 一、先看定义

概念目标关键思想
数据懒加载(Lazy Loading / Infinite Scroll)减少一次加载的数据量当用户滚动到底部时,再从服务器加载更多数据
虚拟列表(Virtual List / Virtual Scrolling)减少同时渲染在 DOM 中的元素数量只渲染可视区域内的那部分数据,其余用空白占位

🔍 二、举例理解

假设你有一个包含 10,000 条评论 的列表:

✅ 1️⃣ 数据懒加载:

  • 一次加载 20 条;
  • 用户滑到底部 → 请求下一页;
  • DOM 最终可能会包含几百甚至几千条数据(会越来越多)。

🧠 核心点:网络层的优化(避免一次性请求太多数据)。


✅ 2️⃣ 虚拟列表:

  • 数据可能已经全部在内存里(例如前端缓存了全部 10,000 条);
  • 但渲染时,只把当前视口中可见的几十条放到 DOM;
  • 滚动时,动态复用这些 DOM 元素(重用节点 + 改内容);
  • 用户感觉像在滚动整个列表,其实页面上只有几十个真实元素。

🧠 核心点:渲染层的优化(减少 DOM 节点,提高渲染性能)。


⚙️ 三、类比理解

类比数据懒加载虚拟列表
📦 像快递分批到达
🧹 像清理房间只展示当前视线内的物品
🧠 优化的层面网络请求、接口性能浏览器渲染、内存占用
📊 数据量变化会越来越多DOM 元素数量固定(数据量大)

🧩 四、两者可以结合使用!

在实际项目中,它们经常一起用

💡 “懒加载 + 虚拟列表” = 真正的高性能大数据滚动列表

例如:

  • 先用懒加载分批请求数据(每次加载 50 条);
  • 然后在前端用虚拟列表技术,只渲染当前视口的 10 条左右;
  • 这样即节省网络流量,又减少 DOM 压力。

💻 五、简单示意对比

懒加载(Lazy Loading)

懒加载的核心目标是:

不要一次请求所有数据,只在用户需要的时候才加载更多。


✅ 实现思路

  1. 初次加载:从服务器请求第一页数据(例如 20 条);
  2. 监听滚动事件:检测用户是否滚动到底部;
  3. 触底加载:如果接近底部,发起新的请求;
  4. 追加渲染:把新数据追加到已有列表中;
  5. 防抖节流:避免用户频繁滚动导致重复请求。

💻 示例代码(基础版)
<div id="list"></div>
<div id="loading">加载中...</div>

<script>
let page = 1;
let isLoading = false;

async function loadData() {
  if (isLoading) return;
  isLoading = true;
  document.getElementById('loading').style.display = 'block';

  // 模拟请求接口
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts?_page=${page}&_limit=10`);
  const data = await res.json();

  const list = document.getElementById('list');
  data.forEach(item => {
    const div = document.createElement('div');
    div.textContent = `${item.id}. ${item.title}`;
    div.className = 'item';
    list.appendChild(div);
  });

  document.getElementById('loading').style.display = 'none';
  page++;
  isLoading = false;
}

// 初始加载
loadData();

// 监听滚动事件
window.addEventListener('scroll', () => {
  const scrollBottom = window.scrollY + window.innerHeight >= document.body.scrollHeight - 50;
  if (scrollBottom) {
    loadData();
  }
});
</script>

🧠 原理总结:

懒加载主要是靠滚动检测 + 异步加载 + 数据追加来实现的。


🧭 虚拟列表(Virtual List)

虚拟列表的目标是:

只渲染视口内的元素,用“占位高度”假装整个列表都渲染了。

当你有几千个项目时,不可能把它们都塞进 DOM(会非常卡)。
虚拟列表通过“窗口化渲染”来解决这个问题。


✅ 实现思路
  1. 计算每个元素的高度(或固定高度);
  2. 根据滚动位置计算可见范围
  3. 只渲染可见的数据子集
  4. 通过一个“填充容器”保持整体滚动高度不变

💻 示例代码(简易虚拟列表)
<div id="viewport" style="height:300px;overflow:auto;border:1px solid #ccc;">
  <div id="spacer"></div> <!-- 用于撑起总高度 -->
  <div id="content" style="position:absolute;top:0;left:0;right:0;"></div>
</div>

<script>
const total = 10000;        // 总数据条数
const itemHeight = 30;      // 每项高度
const viewport = document.getElementById('viewport');
const spacer = document.getElementById('spacer');
const content = document.getElementById('content');

spacer.style.height = `${total * itemHeight}px`; // 撑起总高度

function render() {
  const scrollTop = viewport.scrollTop;
  const start = Math.floor(scrollTop / itemHeight);
  const visibleCount = Math.ceil(viewport.clientHeight / itemHeight);
  const end = start + visibleCount;

  // 计算当前可视区域的偏移
  content.style.transform = `translateY(${start * itemHeight}px)`;

  // 渲染可视区域的列表项
  content.innerHTML = '';
  for (let i = start; i < end && i < total; i++) {
    const div = document.createElement('div');
    div.textContent = `${i + 1}`;
    div.style.height = `${itemHeight}px`;
    div.style.borderBottom = '1px solid #eee';
    content.appendChild(div);
  }
}

viewport.addEventListener('scroll', render);
render();
</script>

🧠 原理总结:

虚拟列表是通过 只渲染视口数据 + 用空白元素撑高滚动条 来实现“假滚动”。


💡 混合使用实现逻辑示意
// 懒加载控制数据量
if (接近底部 && 还有更多数据) {
  fetchNextPageData(); // 网络层懒加载
}

// 虚拟列表控制渲染量
visibleItems = allData.slice(start, end); // 渲染层虚拟化

🧠 六、总结一句话区分

🔹 数据懒加载:控制“请求多少数据”;
🔹 虚拟列表:控制“渲染多少 DOM”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YiHanXii

呜呜呜我想喝奶茶

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值