大数据表格如何渲染?
维格表、飞书表格、钉钉表格,在线表格追求大数据量
1.数据足够大,大数据公司,需要在前端展示大量数据,以往防卡顿,所以我们想要通过更好方案实现。
2.我作为负责人,调研这部分方案
1.dom
2.虚拟表格
3.canvas table
4.可视区绘制算法优化
5.canvas 结合 Webassembly 技术实现(skia + Webassembly)
3.我封装了画布表格引擎,解决了上述问题,并且能够实现 1000w 数据加载流畅交互
4.在这个过程中遇到那些问题,我是怎么解决问题的,卡点
虚拟表格
- 虚拟表格的基本原理
虚拟表格的核心思想是只渲染用户当前可见的部分数据,而不是一次性渲染整个数据集。通过这种方式,可以显著减少DOM节点的数量,从而提高渲染性能和用户交互的流畅性。 - 实现步骤
数据分片:将大数据集分成多个小块,只在用户滚动时加载当前可见区域的数据。
计算可见区域:根据用户的滚动位置,计算出当前可见的行数和列数。
动态渲染:根据可见区域的数据动态渲染表格,只在DOM中插入当前可见的数据行。
占位符:为了保持表格的整体布局,可以使用占位符来填充未渲染的行,确保表格的高度和宽度保持一致。 - 第三方的插件虚拟表格插件
vxe-table
代码
<template>
<div>
<vxe-table
:data="tableData"
:scroll-y="{ enabled: true }"
:scroll-x="{ enabled: true }"
:height="tableHeight"
:max-height="maxHeight"
:column-config="{ resizable: true }"
:size="'medium'"
stripe
border
:virtual-scroll="{ enabled: true }"
>
<vxe-column field="id" title="ID" width="100"></vxe-column>
<vxe-column field="name" title="Name" width="200"></vxe-column>
<vxe-column field="age" title="Age" width="100"></vxe-column>
<!-- 其他列 -->
</vxe-table>
</div>
</template>
<script>
export default {
data() {
return {
tableData: [], // 用于存储大数据
tableHeight: 600, // 表格高度
maxHeight: 800, // 最大高度
};
},
created() {
this.loadData();
},
methods: {
loadData() {
// 模拟加载大数据
const data = [];
for (let i = 0; i < 1000000; i++) {
data.push({
id: i,
name: `Name ${i}`,
age: Math.floor(Math.random() * 100),
});
}
this.tableData = data;
},
},
};
</script>
<style>
/* 你可以在这里添加自定义样式 */
</style>
canvas table
-
基本原理
Canvas 是一种图形绘制技术,可以直接在网页上绘制图形和文本。通过使用 Canvas,我们可以在一个画布上绘制表格的可见部分,而不是在 DOM 中创建大量的元素。这种方式可以显著提高渲染性能。 -
代码
<template>
<div>
<canvas id="dataTableCanvas" width="800" height="600"></canvas>
</div>
</template>
<script>
export default {
data() {
return {
canvas: null,
ctx: null,
tableData: [], // 存储大数据
rowHeight: 30, // 每行高度
visibleRows: 20, // 可见行数
scrollTop: 0, // 当前滚动位置
};
},
mounted() {
this.canvas = document.getElementById('dataTableCanvas');
this.ctx = this.canvas.getContext('2d');
this.loadData();
this.drawTable();
this.canvas.addEventListener('scroll', this.onScroll);
},
methods: {
loadData() {
// 模拟加载大数据
const data = [];
for (let i = 0; i < 1000000; i++) {
data.push({
id: i,
name: `Name ${i}`,
age: Math.floor(Math.random() * 100),
});
}
this.tableData = data;
},
drawTable() {
const startRow = Math.floor(this.scrollTop / this.rowHeight);
const endRow = startRow + this.visibleRows;
// 清空画布
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// 绘制表头
this.ctx.fillStyle = '#f0f0f0';
this.ctx.fillRect(0, 0, this.canvas.width, this.rowHeight);
this.ctx.fillStyle = '#000';
this.ctx.fillText('ID', 10, 20);
this.ctx.fillText('Name', 100, 20);
this.ctx.fillText('Age', 300, 20);
// 绘制数据行
for (let i = startRow; i < endRow && i < this.tableData.length; i++) {
const row = this.tableData[i];
this.ctx.fillStyle = '#fff';
this.ctx.fillRect(0, (i - startRow + 1) * this.rowHeight, this.canvas.width, this.rowHeight);
this.ctx.fillStyle = '#000';
this.ctx.fillText(row.id, 10, (i - startRow + 1) * this.rowHeight + 20);
this.ctx.fillText(row.name, 100, (i - startRow + 1) * this.rowHeight + 20);
this.ctx.fillText(row.age, 300, (i - startRow + 1) * this.rowHeight + 20);
}
},
onScroll(event) {
this.scrollTop = event.target.scrollTop;
this.drawTable();
},
},
};
</script>
<style>
/* 你可以在这里添加自定义样式 */
</style>
- 关键点说明
Canvas 绘制:使用 fillRect 和 fillText 方法在 Canvas 上绘制表格的行和列。
滚动处理:通过监听 Canvas 的滚动事件,更新 scrollTop 并重新绘制可见区域的表格。
性能优化:由于 Canvas 只绘制可见区域,避免了大量 DOM 操作,从而提高了性能。
canvas 结合 Webassembly 技术实现(skia + Webassembly)
要实现一个结合 Canvas 和 WebAssembly 的表格渲染方案,使用 Skia Graphics Library 是一个很好的选择。Skia 是一个开源的 2D 图形库,广泛用于 Google 的产品中。通过 WebAssembly,可以将 Skia 编译为可以在浏览器中运行的代码,从而实现高性能的图形渲染。
实现步骤
以下是一个简化的实现步骤,展示如何使用 Skia 和 WebAssembly 来渲染一个表格。请注意,这个过程涉及多个步骤,包括设置开发环境、编译 Skia、编写 WebAssembly 代码等。
- 环境准备
首先,你需要安装以下工具:
Emscripten:用于将 C++ 代码编译为 WebAssembly。
Skia:下载并构建 Skia。
安装 Emscripten
请参考 Emscripten 官方文档 进行安装。
下载和构建 Skia - 克隆 Skia 仓库:
git clone https://skia.googlesource.com/skia.git
cd skia
-
按照 Skia 的构建说明进行设置,确保使用 Emscripten 作为编译器。
-
编写 C++ 代码
创建一个 C++ 文件,例如 table_renderer.cpp,用于渲染表格。
#include "include/core/SkCanvas.h"
#include "include/core/SkPaint.h"
#include "include/core/SkStream.h"
#include "include/core/SkSurface.h"
#include "include/core/SkImage.h"
#include "include/core/SkFont.h"
#include "include/core/SkTypeface.h"
extern "C" {
void render_table(SkCanvas* canvas) {
SkPaint paint;
paint.setColor(SK_ColorWHITE);
canvas->drawRect(SkRect::MakeWH(800, 600), paint); // 背景
// 绘制表头
paint.setColor(SK_ColorGRAY);
canvas->drawRect(SkRect::MakeXYWH(0, 0, 800, 30), paint);
paint.setColor(SK_ColorBLACK);
paint.setTextSize(20);
canvas->drawString("ID", 10, 20, paint);
canvas->drawString("Name", 100, 20, paint);
canvas->drawString("Age", 300, 20, paint);
// 绘制数据行
for (int i = 0; i < 100; i++) {
paint.setColor(i % 2 == 0 ? SK_ColorWHITE : SK_ColorLTGRAY);
canvas->drawRect(SkRect::MakeXYWH(0, (i + 1) * 30, 800, 30), paint);
paint.setColor(SK_ColorBLACK);
canvas->drawString(std::to_string(i).c_str(), 10, (i + 1) * 30 + 20, paint);
canvas->drawString(("Name " + std::to_string(i)).c_str(), 100, (i + 1) * 30 + 20, paint);
canvas->drawString(std::to_string(rand() % 100).c_str(), 300, (i + 1) * 30 + 20, paint);
}
}
}
- 编译 C++ 代码为 WebAssembly
使用 Emscripten 编译 C++ 代码为 WebAssembly:
emcc table_renderer.cpp -o table_renderer.js -s WASM=1 -s EXPORTED_FUNCTIONS='["_render_table"]' -I/path/to/skia/include -L/path/to/skia/out/ -lskia
- 创建 HTML 文件
创建一个 HTML 文件 index.html,用于加载 WebAssembly 模块并渲染表格。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Skia + WebAssembly Table</title>
<script src="table_renderer.js"></script>
</head>
<body>
<canvas id="canvas" width="800" height="600"></canvas>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// 等待 WebAssembly 加载
Module.onRuntimeInitialized = () => {
const skiaCanvas = new SkCanvas(ctx); // 假设有 SkCanvas 类
Module._render_table(skiaCanvas); // 调用 C++ 渲染函数
};
</script>
</body>
</html>
- 运行项目
- 使用一个本地服务器(如 http-server 或 live-server)来运行项目。
- 打开浏览器,访问相应的 URL,你应该能够看到使用 Skia 和 WebAssembly 渲染的表格。
WebAssembly与用canvas table 实现大数据表格的区别
- 性能
WebAssembly:
WebAssembly(Wasm)是一种低级字节码格式,旨在提供接近原生性能的执行速度。它允许开发者使用 C/C++ 等语言编写高性能的代码,并在浏览器中运行。
使用 WebAssembly 和图形库(如 Skia)可以实现高效的图形渲染,适合需要复杂计算和高性能渲染的场景。
Canvas Table:
使用 Canvas API 直接在 JavaScript 中绘制图形和文本,性能相对较低,尤其是在处理大量 DOM 操作时。
对于简单的表格渲染,Canvas 可以提供足够的性能,但在处理复杂的图形或大量数据时,可能会出现性能瓶颈。
- 开发复杂性
WebAssembly:
开发过程相对复杂,需要设置编译工具链(如 Emscripten),并编写 C/C++ 代码。
需要处理与 JavaScript 的交互,可能涉及更多的学习曲线。
Canvas Table:
使用 JavaScript 和 HTML5 Canvas API,开发相对简单,易于上手。
适合快速原型开发和简单的表格展示。
- 适用场景
WebAssembly:
适合需要高性能计算和复杂图形渲染的应用,如游戏、图形编辑器、数据可视化等。
当需要处理大量数据并进行复杂计算时,WebAssembly 可以显著提高性能。
Canvas Table:
适合简单的表格展示和交互,尤其是在数据量不大的情况下。
对于需要快速开发和简单实现的场景,Canvas 是一个不错的选择。
- 生态系统和工具支持
WebAssembly:
生态系统相对较新,虽然有许多库和工具支持,但仍在不断发展中。
需要依赖于其他图形库(如 Skia)来实现复杂的图形渲染。
Canvas Table:
有丰富的文档和社区支持,许多现成的库和框架(如 vxe-table、ag-Grid 等)可以帮助快速实现表格功能。
直接使用 JavaScript 和 HTML,易于集成和使用。
总结
WebAssembly 提供了更高的性能和更复杂的图形处理能力,适合需要高效渲染和计算的应用场景,但开发复杂性较高。
Canvas Table 更加简单易用,适合快速开发和简单的表格展示,但在处理大量数据时性能可能不足。
支持
WebAssembly:
生态系统相对较新,虽然有许多库和工具支持,但仍在不断发展中。
需要依赖于其他图形库(如 Skia)来实现复杂的图形渲染。
Canvas Table:
有丰富的文档和社区支持,许多现成的库和框架(如 vxe-table、ag-Grid 等)可以帮助快速实现表格功能。
直接使用 JavaScript 和 HTML,易于集成和使用。
总结
WebAssembly 提供了更高的性能和更复杂的图形处理能力,适合需要高效渲染和计算的应用场景,但开发复杂性较高。
Canvas Table 更加简单易用,适合快速开发和简单的表格展示,但在处理大量数据时性能可能不足。
选择哪种技术取决于具体的应用需求、性能要求和开发团队的技术栈。
1431

被折叠的 条评论
为什么被折叠?



