vue3.2 +vxetable4.6 渲染大数据列,出现错乱问题处理方案
概要
在vue项目中,有时候需要渲染大量的动态列,在我的项目中当我的列达到150个以上时,出现了列错乱问题,以下是我的示例截图
查看官网渲染大数据时使用虚拟滚动
横向虚拟滚动
通过 scroll-x.enabled 与 scroll-x.gt 组合开启,其中 enabled 为总开关,gt 是指当总列数大于指定列数时自动开启。
理论上限:横向平均上限支持 8w 列(最大上限 20w 列)。当 gt 为 0 时为总是启用。
性能优化:横向虚拟滚动列宽越宽越流畅,列宽设置 column.width | column.min-width
小提示
启用横向虚拟滚动,建议开启 show-header-overflow 和 show-footer-overflow 获得最高渲染性能
按照官网设置之后,数据量大时依旧错乱,升级版本等各种方法使用之后还是不行
解决方案
requestAnimationFrame
requestAnimationFrame是浏览器用于定时循环操作的一个接口,类似于setTimeout,主要用途是按帧对网页进行重绘,让各种网页动画效果(DOM动画、Canvas动画、SVG动画、WebGL动画)能够有一个统一的刷新机制,从而节省系统资源,提高系统性能,改善视觉效果。
在运行过程中,window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行
这个是在之前做动画的时候用过,抱着试试的心态,我修改了一下我的代码发现可以!
小结
当使用vxe-table 遇到大数据渲染错乱时,其他方案都不行时,可以试一下requestAnimationFrame
源码
<template>
<div class="app-container">
<a-space style="margin-bottom: 10px">
<a-range-picker v-model:value="dates" />
<a-button type="primary" @click="onSearch">查询</a-button>
</a-space>
<vxe-table
:data="tableData"
:height="800"
v-loading="loading"
border
show-overflow
show-header-overflow
show-footer-overflow
:scroll-x="{ enabled: true, gt: 0 }"
>
<vxe-column
title="名称"
field="name"
width="100"
fixed="left"
></vxe-column>
<vxe-column
title="编码"
field="code"
width="100"
fixed="left"
></vxe-column>
<vxe-column
title="数量"
field="count"
width="100"
fixed="left"
></vxe-column>
<vxe-column
v-for="item in columns"
:key="item.field"
:field="item.field"
:title="item.title"
:min-width="item.minWidth"
></vxe-column>
</vxe-table>
</div>
</template>
<script setup>
import dayjs from 'dayjs'
const dates = ref([])
const tableData = ref([])
const loading = ref(false)
const columns = ref([])
const onSearch = () => {
loading.value = true
setTimeout(() => {
requestAnimationFrame(() => {
columns.value = getColums()
})
tableData.value = getData()
loading.value = false
}, 1000)
}
const getColums = () => {
if (!dates || dates.value.length === 0) {
return []
}
const [start, end] = dates.value
const diff = dayjs(end).diff(dayjs(start), 'day')
const columns = []
for (let i = 0; i <= diff; i++) {
const date = dayjs(start).add(i, 'day').format('YYYY-MM-DD')
columns.push({
field: date,
title: date,
minWidth: 100
})
}
return columns
}
const getData = () => {
const columns = getColums()
if (!columns || columns.length === 0) {
return []
}
const data = []
for (let i = 0; i < 100; i++) {
const row = {
name: `name${i}`,
code: `code${i}`,
count: i
}
for (const col of columns) {
row[col.field] = Math.floor(Math.random() * 100)
}
data.push(row)
}
return data
}
</script>
<style scoped lang="scss">
.app-container {
padding: 10px;
}
</style>