Vue实现虚拟滚动渲染海量数据的原理与代码示例

作者:南栀

时间:2026-10-26

浏览:591

本文介绍如何在Vue中通过虚拟滚动技术解决渲染成千上万条数据导致的浏览器卡顿问题。核心思路是仅渲染可视区域内的DOM,利用占位元素维持滚动高度,并通过监听滚动事件动态计算可见数据范围,结合CSS定位与变换实现无感滚动效果。

文章目录

虚拟滚动原理与性能优势

在网页中直接渲染成千上万个DOM元素,极易导致浏览器响应迟缓甚至崩溃。采用虚拟滚动是解决这一性能瓶颈的有效方案之一。其核心机制在于页面始终只渲染当前可视区域内的DOM节点,当用户触发滚动操作时,系统依据当前的滚动高度动态更新可视区内的DOM内容,从而实现流畅且无感知的滚动体验。

Vue虚拟滚动实现思路

实现该功能的基本思路如下:

  • 首先,根据数据总条数计算出列表所需的总高度,并创建一个具有该高度的DOM元素作为占位符。这一步确保了滚动条能够正常显示,允许用户自由滚动整个列表区域。
  • 接着,为滚动容器监听scroll事件,以捕获用户的滚动行为。
  • 在滚动事件中,依据当前的scrollTop值,利用数组的slice方法截取当前可视范围内对应的数据下标及内容。
  • 同时,根据scrollTop的值动态控制虚拟列表容器的偏移位置,确保数据始终准确显示在用户的可视区域内。
  • 此外,在可视区域的上方和下方需额外预留一部分DOM节点。这一措施旨在防止用户滚动速度过快时,新数据尚未加载完毕而出现短暂的白屏现象。
  • 在样式实现上,建议采用fixed或absolute定位结合transform属性来移动列表。这种方式可以有效避免页面发生回流(reflow),从而提升渲染性能。

尽管涉及逻辑较多,但实际代码量并不多,关键在于透彻理解上述实现思路。

Vue虚拟滚动代码示例

<template>
  <div class="device">
    <div class="vir-scroll">
      <div class="scroll-Y" @scroll="scroll">
        <div class="parentDom">
          <!-- 占位,根据数据条数生成滚动列表 -->
          <div :style="{ height: screenHeight + 'px' }"></div>
           <!-- 虚拟滚动列表 -->
          <div class="positionRelative" :style="{ transform: getTransform }">
            <div class="scroll-item" v-for="item in visibleData" :key="item.index">
              <div class="scroll-info">helloworld</div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      /** 数据列表 */
      dataList: [],
      /** 单行高度 */
      itemHeight: 143,
      /** 偏移高度 */
      startOffset: 0,
      /** 起始显示数据 */
      start: 0,
      /** 结束显示数据 */
      end: 10,
    }
  },
  computed: {
    /** 根据每条数据的高度获取总列表高度 */
    screenHeight() {
      return this.dataList.length * this.itemHeight
    },
    /** 前面预留 */
    prevCount() {
      return 8
    },
    /** 后面预留 */
    nextCount() {
      return 25
    },
    /** 每次截取虚拟列表的位置 */
    getTransform() {
      return `translate(0,${this.startOffset}px)`
    },
    /** 虚拟数据 */
    visibleData() {
      return this.dataList.slice(this.start, Math.min(this.end, this.dataList.length))
    },
  },
  methods: {
    /** 列表滚动,暂时不节流,因为滚动快触发次数就少,容易导致没有及时更新数组导致白屏 */
    scroll(e) {
      this.scrollThrottle(e.target.scrollTop)
    },
    /** 滚动函数 */
    scrollThrottle(scrollTop) {
      const topCount = Math.floor(scrollTop / this.itemHeight) - this.prevCount
      // 此时的开始索引
      this.start = topCount >= 0 ? topCount : 0
      // 此时的结束索引
      this.end = this.start + this.nextCount
      // 此时的偏移量
      this.startOffset = this.start * this.itemHeight
    },
  },
}
</script>
<style scoped lang="scss">
.device {
  .vir-scroll {
    // 脱离文档流避免回流
    position: fixed;
    left: 0;
    width: 100%;
    height: calc(100% - 196px);
    padding: 0 16px;
    z-index: 10;

    .scroll-Y {
      width: 100%;
      height: 100%;
      overflow-y: auto;

      .parentDom {
        position: relative;

        .positionRelative {
          width: 100%;
          position: absolute;
          left: 0;
          top: 0;
          border-radius: 5px;
          padding-bottom: 12.5px;

          .scroll-item {
            height: 143px;
            background-color: #ffffff;
            font-size: 12px;
            padding: 10px 15px 0px 15px;
          }
        }
      }
    }
  }
}
</style>

至此,关于在Vue中通过虚拟滚动技术渲染海量数据的介绍已完成。如需了解更多相关Vue虚拟滚动内容,建议查阅本站往期文章或继续浏览后续相关教程,感谢大家的支持!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章