我的需求
同时在一个表格中显示6个甚至更多的传感器数据,数据量在每个传感器每10秒1条数据,一般请求1天的数据。
以6个传感器计算一下数据量:
6 * 24 * 60 * 6 = 51840
一次只能请求到1个传感器的数据,也就是8640条,当查询时间范围变化时,循环请求接口获取数据,并且需要很快的渲染完毕。
效果像这样

我的经历
先使用的 Table(el-table)
调用一次接口反应时间(浏览器网络窗口查看)约在1-2s左右,一次接口的数据使用Table渲染一次时间约是4s左右。
最开始的想法
新添加一个传感器的数据,每一次需要重新渲染一次没有问题。
当切换查询时间后,循环调用时,采用的是------给tableData中直接添加。这会导致在循环调取数据时,每调取一次就会重新渲染一次。出现渲染卡顿问题,6个接口调用完毕且渲染完成,需要20-30s的时间,数据量大的时间会更长,有兴趣的朋友可以试一下。
js
<el-table v-loading="loading" element-loading-text="数据加载中":data="tableData"
height="100%">
<el-table-column :min-width="leftWidth" :fixed="index == 0" v-for="(column, index) in columns"
:key="column.prop" :label="column.label" :prop="column.prop"></el-table-column>
</el-table>
······
tableData.value = tableData.value.map((item: any, index: number) => {
return {
...item,
['data' + String(sensor.id)]: Number(res.data.Data[index].data).toFixed(3)
}
})
对最开始的想法优化
在循环调用时,调用一次渲染一次非常慢,第一次优化是拿到所有的数据之后,再将数据添加至tableData,之后同意进行渲染,这种方式快了一点,但没有太大改善。
js
const buildTableFromAllData = (allFetched: Array<any>) => {
if (allFetched.length === 0) return;
// 第一步:构建 columns
const newColumns = [
{ prop: 'time', label: '时间' }
];
allFetched.forEach(({ device, gateway }) => {
newColumns.push({
prop: 'data' + String(sensor.id),
label: sensor.name
});
});
// 第二步:对齐时间轴(假设所有设备返回的时间点一致)
const firstData = allFetched[0].rawData;
const timeList = firstData.map((item: any) => dayjs(item.time).format('YYYY-MM-DD HH:mm:ss'));
// 第三步:构建 tableData 行数据
const newTableData = timeList.map((time: string, index: number) => {
const row: Record<string, any> = { time };
allFetched.forEach((_, colIndex) => {
const value = allFetched[colIndex].rawData[index]?.data;
const formatted = value ? Number(value).toFixed(3) : '';
row['data' + String(_.sensor.id)] = formatted;
});
return row;
});
// 第四步:构建 lineData(用于图表)
const newLineData = allFetched.map(fetched =>
fetched.rawData.map((item: any) => Number(item.data).toFixed(3))
);
// ✅ 一次性赋值!只触发一次响应式更新
columns.value = newColumns;
tableData.value = newTableData;
};
虚拟化表格的接触
在AI的建议下使用虚拟化表格。
ElementPlus中的说明通过虚拟化表格组件,超大数据渲染将不再是一个头疼的问题。
使用虚拟化表格之后,渲染速度至少提升一半时间以上。
js
<el-auto-resizer>
<template #default="{ height, width }">
<el-table-v2 v-loading="loading" element-loading-text="数据加载中" :columns="columns" :data="tableData"
:width="width" :height="height" fixed />
</template>
</el-auto-resizer>
······
const buildTableFromAllData = (allFetched: Array<any>) => {
if (allFetched.length === 0) return;
const newColumns: any[] = [
{
key: 'time',
dataKey: 'time',
title: '时间',
width: 200 * Number(ratio.value),
fixed: 'left'
}
];
allFetched.forEach(({ sensor }) => {
newColumns.push({
key: 'data' + String(sensor.id),
dataKey: 'data' + String(device.Deviceid),
title: sensor.name,
width: 200 * Number(ratio.value)
})
});
const firstData = allFetched[0].rawData;
const timeList = firstData.map((item: any) => dayjs(item.time).format('YYYY-MM-DD HH:mm:ss'));
const newTableData = timeList.map((time: string, index: number) => {
const row: Record<string, any> = { time };
allFetched.forEach((_, colIndex) => {
const value = allFetched[colIndex].rawData[index]?.data;
const formatted = value ? Number(value).toFixed(3) : '';
row['data' + String(_.sensor.id)] = formatted;
});
return row;
});
const newLineData = allFetched.map(fetched =>
fetched.rawData.map((item: any) => Number(item.data).toFixed(3))
);
// ✅ 一次性赋值!只触发一次响应式更新
columns.value = newColumns;
tableData.value = newTableData;
};
其它问题
问题
其实以上用法已经完全解决了我的问题,但是在电脑浏览器中使用无误,但是一换到手机浏览器或者平板浏览器中,虚拟表格直接滑不动,能看到滚动条,但是就是滑不动,以下是我的解决尝试过程。
AI给的解决方案------添加CSS
查询到滚动的内容是这样的<div class="el-vl__wrapper el-table-v2__body",于是我添加了下面的样式
css
:deep(.el-table-v2__main .el-table-v2__body) {
-webkit-overflow-scrolling: touch !important;
overflow-y: auto !important;
overflow-x: auto !important;
touch-action: pan-x pan-y !important;
}
结果就是没有结果,并没有解决我的问题。
最终解决方案------还是添加CSS,但略有不同
在审查元素的时候发现了一个东西,第二行div中的overflow: hidden;
html
<div class="el-vl__wrapper el-table-v2__body" role="rowgroup">
<div class="" style="position: relative; overflow: hidden; will-change: transform; direction: ltr; height: 1313.11px; width: 2143.33px;"><div style="height: 3000px; width: 2137.33px;">
······
</div>
</div>
怎么给body设置滚动都没有用,因为里面给hidden了,于是添加的CSS变成了这样
css
:deep(.el-table-v2__main .el-table-v2__body) {
-webkit-overflow-scrolling: touch !important;
overflow-y: auto !important;
overflow-x: auto !important;
touch-action: pan-x pan-y !important;
}
OK!成功解决问题,以上就是虚拟化表格的浅用过程,得下次有机会再深入使用!