前端VUE3项目处理大数据动态高度加载方案--虚拟列表滚动

1,403 阅读3分钟

前言

在前端项目中经常会遇到需要加载上千条甚至上万条列表数据的情况,一般都会分页处理,但是当要求分页页码大(如每页500/1000条)同时列表展示面板复杂时,分页渲染也会造成页面渲染卡顿加载慢的性能问题。所以考虑引入虚拟列表滚动加载技术。

项目实现效果图

image.png

思路与方案

项目是基于vue3的,由于项目时间紧迫,采用成熟的第三方库实现虚拟列表。目前市场上比较成熟的开源库有:vue-virtual-scroller。但是vue-virtual-scroller只能支持简单的动态高度,不能支持复杂的动态高度列表。于是在掘金找到一个轻量的虚拟列表滚动库vue3-infinite-list

具体代码

<template>
  <InfiniteList :data="messageList" :width="'100%'" :height="520" :itemSize="getItemSize" :debug="false" v-slot="{ item, index }">
    <div class="li-con">item {{ index }} : {{ item }}</div>
  </InfiniteList>
</template>
<script lang="ts">
export default {
  name: 'order-list'
}
</script>
<script setup lang="ts">
import { ref } from 'vue'
import InfiniteList from 'vue3-infinite-list'

const messageList = ref<any[]>([])
for (let i = 0; i < 1000000; i++) {
  messageList.value.push({
    id: i,
    msg: 'hahahha' + i,
    name: '你好哈' + i
  })
}
// 通过这个函数可以动态设置元素宽高.
const getItemSize = (i: number): number => {
  switch (i % 4) {
    case 1:
      return 80
    case 2:
      return 50
    case 3:
      return 100
    default:
      return 200
  }
}
</script>

<style lang="scss" scoped>
.liveMeg {
  height: 450px;
  flex: 1;
  margin-left: 10px;
  background-color: #252632;
  border-radius: 10px;
  box-shadow: 0 0 10px 2px gray;
  scrollbar-color: #363741 transparent;
  scrollbar-width: thin;
  overflow-y: scroll;
  .msgBox {
    display: flex;
    flex-direction: row;
    padding: 5px;
    white-space: wrap;
    .name {
      color: #8ce7ff;
      margin-right: 2px;
      white-space: nowrap;
    }
    .msg {
      color: white;
      white-space: wrap;
    }
  }
}
.scroller {
  height: 400px;
}
.user {
  height: 32%;
  padding: 0 12px;
  display: flex;
  align-items: center;
}
</style>

遇到的问题和解决方案

1.因为项目中列表每一行高度是不确定的,vue3-infinite-list库并不能自动识别渲染每一行的动态高度,所以利用itemSize属性动态配置每一行的高度。(只能自己手动计算动态高度,组件并不能自动渲染计算动态高度)
2.存在bug:当高度大于777px时出现不了滚动条问题。(我是根据浏览器高度来设置height参数的,但是当我height超出777px时,内部不会出现滚动条了,因为他的计算高度最高就是777px,但实际上不是)
解决方案:

// 默认设置组件的高度为500px
const tableHeight = ref('500px')

// 写在数据渲染完成后
const actualHeight = getTableHeight(data) // 获取表格数据加载的实际总高度
if (actualHeight < parseInt(tableHeight.value)) {
  // 当实际总高度小于500时,则直接赋值实际高度,避免表格和分页中间还有一块空白区域
  tableHeight.value = actualHeight + 'px'
} else {
  // 当实际总高度大于500时,这只表格的高度,设置滚动条,解决滚动条不显示问题
  setTimeout(() => {
    const dom = document.querySelector('表格dom') as HTMLElement
    if (dom) {
      dom.style.height = actualHeight + 'px'
      const parentDom = document.querySelector('.表格的父级dom') as HTMLElement
      parentDom.scrollTop = 1
      setTimeout(() => {
        parentDom.scrollTop = 0
      }, 50)
    }
  }, 50)
}

文献参考

掘金vue3-infinite-listjuejin.cn/post/707963…
githubvue3-infinite-list::github.com/tnfe/vue3-i…
掘金vue-virtual-scrollerwww.jianshu.com/p/9d810843f…