普通视图

发现新文章,点击刷新页面。
今天 — 2025年11月28日首页

浅记一下ElementPlus中的虚拟化表格(el-table-v2)的简单使用

作者 _瑶瑶_
2025年11月27日 16:49

我的需求

同时在一个表格中显示6个甚至更多的传感器数据,数据量在每个传感器每10秒1条数据,一般请求1天的数据。

以6个传感器计算一下数据量:

6 * 24 * 60 * 6 = 51840

一次只能请求到1个传感器的数据,也就是8640条,当查询时间范围变化时,循环请求接口获取数据,并且需要很快的渲染完毕。

效果像这样

image.png

我的经历

先使用的 Table(el-table)

调用一次接口反应时间(浏览器网络窗口查看)约在1-2s左右,一次接口的数据使用Table渲染一次时间约是4s左右。

最开始的想法

新添加一个传感器的数据,每一次需要重新渲染一次没有问题。

当切换查询时间后,循环调用时,采用的是——给tableData中直接添加。这会导致在循环调取数据时,每调取一次就会重新渲染一次。出现渲染卡顿问题,6个接口调用完毕且渲染完成,需要20-30s的时间,数据量大的时间会更长,有兴趣的朋友可以试一下。

<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,之后同意进行渲染,这种方式快了一点,但没有太大改善。

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中的说明通过虚拟化表格组件,超大数据渲染将不再是一个头疼的问题

使用虚拟化表格之后,渲染速度至少提升一半时间以上。

<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",于是我添加了下面的样式

: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;

<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变成了这样

: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!成功解决问题,以上就是虚拟化表格的浅用过程,得下次有机会再深入使用!

❌
❌