uniapp 虚拟列表如何实现高性能渲染

在uniapp中实现虚拟列表时,如何确保高性能渲染?目前遇到长列表渲染卡顿的问题,尤其是数据量超过1000条时页面滚动明显不流畅。希望了解具体的优化方案,比如是否要配合scroll-view或自定义组件实现?是否有必要进行DOM节点回收?最好能提供示例代码或性能对比方案。

2 回复

使用 uv-list 组件,结合 use-virtual 插件。只渲染可视区域内的列表项,通过动态计算位置和高度,减少 DOM 节点数量。注意设置正确的 item 高度,避免频繁重排。


在UniApp中实现高性能虚拟列表,主要通过以下方式:

核心实现原理

虚拟列表的核心思想是只渲染可视区域内的元素,通过动态计算和位置调整来模拟完整列表。

具体实现代码

// template部分
<template>
  <view class="virtual-list">
    <view 
      class="list-container" 
      :style="{ height: totalHeight + 'px' }"
      @scroll="handleScroll"
    >
      <view class="phantom" :style="{ height: totalHeight + 'px' }"></view>
      <view 
        class="list-content" 
        :style="{ transform: `translateY(${offset}px)` }"
      >
        <view 
          v-for="item in visibleData" 
          :key="item.id"
          class="list-item"
          :style="{ height: itemHeight + 'px' }"
        >
          {{ item.content }}
        </view>
      </view>
    </view>
  </view>
</template>

// script部分
export default {
  data() {
    return {
      listData: [], // 完整数据源
      itemHeight: 60, // 每项固定高度
      visibleCount: 0, // 可见区域可显示的数量
      startIndex: 0, // 起始索引
      endIndex: 0, // 结束索引
      offset: 0, // 偏移量
    }
  },
  computed: {
    // 列表总高度
    totalHeight() {
      return this.listData.length * this.itemHeight
    },
    // 可视区域数据
    visibleData() {
      return this.listData.slice(this.startIndex, this.endIndex)
    }
  },
  mounted() {
    this.calculateVisibleCount()
    this.updateVisibleData()
  },
  methods: {
    // 计算可见区域能显示的数量
    calculateVisibleCount() {
      const query = uni.createSelectorQuery().in(this)
      query.select('.list-container').boundingClientRect()
      query.exec((res) => {
        if (res[0]) {
          this.visibleCount = Math.ceil(res[0].height / this.itemHeight) + 5 // 缓冲几项
          this.endIndex = this.startIndex + this.visibleCount
        }
      })
    },
    // 滚动处理
    handleScroll(e) {
      const scrollTop = e.detail.scrollTop
      this.startIndex = Math.floor(scrollTop / this.itemHeight)
      this.endIndex = this.startIndex + this.visibleCount
      this.offset = this.startIndex * this.itemHeight
    },
    // 更新可见数据
    updateVisibleData() {
      this.endIndex = Math.min(this.startIndex + this.visibleCount, this.listData.length)
    }
  }
}

性能优化要点

  1. 固定高度:使用固定item高度便于计算
  2. 缓冲区域:可视区域上下多渲染几项,避免快速滚动白屏
  3. 节流处理:对scroll事件进行节流,避免频繁计算
  4. 复用DOM:通过translateY移动整个可视区域,而不是重新创建DOM

动态高度处理

如果item高度不固定,需要预先计算并缓存每个item的高度,计算逻辑会更复杂。

这种实现方式能显著提升长列表的渲染性能,避免内存溢出和卡顿问题。

回到顶部