游乐游手机版
首页/前端开发/文章详情

Vue3虚拟列表实现十万条数据流畅渲染

时间:2026-06-13 06:55
虚拟滚动通过只渲染可视区域数据解决大数据量列表性能问题。固定高度方案利用偏移量与translate3d提升渲染效率;动态高度方案采用位置缓存和二分查找定位,配合节流与预加载机制,实现流畅滚动。

1. 技术背景:虚拟滚动为何成为大数据量列表的解决方案

当列表数据量达到数千甚至上万条时,传统的渲染方式会尝试将全部 DOM 节点一次性插入页面,结果必然导致严重的性能瓶颈——页面卡顿明显、滚动响应迟钝,用户体验急剧下滑。那么,是否存在一种方案既能完整呈现数据集,又不会拖累浏览器性能?答案是肯定的。虚拟滚动(Virtual Scrolling)正是为解决这一痛点而生的前端优化技术。

其核心设计思路非常清晰:仅渲染当前可视区域内的那一部分数据,而不可见的内容在 DOM 中完全不出现。这样一来,无论列表后方有多少条数据,屏幕上始终只维持有限的节点数量,渲染效率与滚动流畅度均得到显著提升。

十万条数据怎么办?Vue3虚拟列表让你纵享丝滑

2. 固定高度方案(v1):基础实现与核心逻辑

2.1 核心实现原理

固定高度版本的实现遵循一个直观的思路:

  • 采用一个固定高度的容器作为“视口”,相当于一扇窗户,用户透过它看到的即是列表当前展示的内容。
  • 同时放置一个与全部数据总高度相等的占位元素,用于撑开滚动条——没有这个滚动“尾巴”,浏览器无法感知还有大量数据未被查看。
  • 接下来需要动态计算:随着滚动条的滑动,实时算出当前视口中应该呈现哪些数据,然后仅渲染这些元素。
  • 最后借助 translate3d 精确控制列表项的位置,这种方式性能出色,且不会触发回流与重排。

2.2 关键代码解析

模板结构


Props 定义

const props = defineProps<{
  items: any[]; // 列表数据
  remain: number; // 显示个数
  size: number; // 每个元素的高度
}>();

核心状态管理

此处通过 startend 标记当前屏幕应显示数据的起始与结束索引。但有一个关键细节:滚动时列表项可能只移动了一半,如果仅渲染完整的 start 到 end 区间,就可能出现空白区域。因此需要在前后各多加载一些数据,相当于准备约三个屏幕的数据量。

此外,利用 offset 控制列表外层容器的偏移量——用户每完整滑过一个项,偏移量就累加一个项的高度。最终对传入的总数据进行截取,只渲染屏幕所需的那部分,从而达到性能优化的目标。

// 数组的起始值
const start = ref(0);
const end = ref(props.remain);
// 数组渲染dom的偏移量
const offset = ref(0);// 前面预先加载的个数
const prevCount = computed(() => {
  return Math.min(start.value, props.remain);
});
// 后面预先加载的个数
const nextCount = computed(() => {
  return Math.min(props.items.length - end.value, props.remain);
});
// 计算当前需要显示的数据
const visibleItems = computed(() => {
  const startIndex = start.value - prevCount.value;
  const endIndex = end.value + nextCount.value;
  return props.items.slice(startIndex, endIndex);
});

滚动事件处理

监听滚动事件:获取当前滚动距离,计算在此过程中完整滑过的列表项数量,然后据此重新计算 start 与 end,并同步更新偏移量。

const handleScroll = () => {
  // 滚动的距离
  const scrollTop = viewportRef.value?.scrollTop ?? 0;
  // 滚动过去的完整个数
  const scrollCount = Math.floor(scrollTop / props.size);
  start.value = scrollCount;
  end.value = start.value + props.remain;
  offset.value = start.value * props.size - prevCount.value * props.size;
};

2.3 性能优化策略

  • 仅渲染当前可视区域的元素,大幅削减 DOM 节点数量
  • 借助 CSS 硬件加速(translate3d),避免每次滚动都触发重排
  • 在首尾设置预加载缓冲区,防止快速滚动时出现白屏
  • 利用 Vue 的响应式系统精确更新数据切片,提升计算效率

2.4 使用示例