在可视化搭建的低代码平台中,设计器是一个非常关键的模块,可以帮助用户通过拖拽、配置等方式快速搭建应用界面。
在技术选型方面,目前市面上主流的设计器技术包括基于 HTML/CSS/JavaScript 的 Web 设计器。
在渲染方案方面,主流的设计器通常采用基于虚拟 DOM 的渲染方案,比如 React、Vue 等,这种渲染方案可以提高渲染性能和开发效率,同时也支持组件化开发,使得设计器更加易于维护和扩展。
除了渲染方案,设计器的交互体验也非常重要,为了提高用户体验,主流的设计器通常会提供丰富的交互组件和动画效果,比如拖拽、缩放、动态添加组件等功能,以及实时预览、撤销重做等操作,这些功能会非常考验渲染方案的选择以及研发的设计与开发功底。
所以要设计一个易于使用、高效的低代码平台设计器,我们需要综合考虑技术选型、渲染方案、交互体验等多个方面的因素,本章将会针对设计器中可视化搭建的方案做一些技术上的选型探讨以及介绍一下市面上一些主流设计器的渲染方案。
浏览器渲染的方式
在开始进行渲染方式的选择之前,我们先来了解下在浏览器中渲染视图的常见方案:
- HTML DOM:目前大多数都是使用其来绘制大部分的前端需求,使用起来非常的灵活和便捷,提供了配套全面的事件处理机制来处理相关的交互操作。主打的优势就是其便携性,学习成本低,上手简单容易。不过在内存开销、渲染速度等方面并不是很占优势,是其的薄弱环节;
- Canvas(画布):HTML5 中,提供了 Canvas 画布元素,通过
<canvas/>
和绘制 API 在web页面上呈现图形、动画和图像。与 DOM 不同,Canvas 主打的优势在于灵活性高、性能出色、跨平台渲染等特点。但 Canvas 的上手成本很高,需要了解 JavaScript Canvas 相关画布 api,不支持 SEO 等等缺陷。设立的门槛让很多想尝试的前端同学望而却步; - WebGL:WebGL 是比较新颖成熟的 3D 渲染引擎,主要用于在 Web 浏览器中呈现复杂的 3D 图像和动画。可以实现高性能的 3D 图形渲染和复杂场景绘制。同时支持硬件加速,调用 GPU 资源来渲染图形,极大的提高了渲染速度。基于 WebGL 的 Three.js 深受广大开发者的青睐。不过相应的缺点就是对基础设备有一定的要求,对低端设备不太友好。另外上手困难,不仅仅需要具备前端开发知识,同时也需要了解图形学、数学相关的一些理念和知识;
- SVG:虽然 SVG 也能够在浏览器上绘制内容,但是与上面的几种技术相比,就明显薄弱很多了,不管是从性能上,还是易用程度而言都没有突出的亮点。不过 SVG 在浏览器图形高保真上有自己独有的优势,因此很多时候都会使用 SVG 的图标来保证相关设计的还原度,拥有更好的呈现效果的同时,也拥有比同位图文件更小的体积。
以上是在浏览器渲染视图的各种方案介绍,可以很明显的看出,DOM 与 Canvas 两种方案综合来看优势会比较明显,所以大部分的低代码产品会选择 DOM 和 Canvas 两者其中一个做为渲染器,不排除某些另辟蹊径的特殊项目有其他的选择。
其他平台的策略
上述提到了 DOM 和 Canvas 是比较好的选择,那么不妨先来看看目前市面上比较热门的一些编辑器它们内部究竟是怎么做抉择的呢?
下面只是做一些技术方案的横向对比,不一定是低代码平台,也包含了目前一些比较受欢迎的企业级 D2C 产品。
平台 | DOM | Canvas | 是否开源 |
---|---|---|---|
Retool | ☑️ | 🙅 | |
bubble | ☑️ | 🙅 | |
蓝湖 | ☑️ | 🙅 | |
即时设计 | ☑️ | 🙅 | |
figma | ☑️ | 🙅 | |
lowcode-engine(宜搭) | ☑️ | ☑️ | |
amis | ☑️ | ☑️ |
可以看出上述的 LowCode & D2C 产品,不管是商业化还是开源项目,可视化搭建类型的低代码产品多数都是使用 DOM 方案,而 D2C 类型的产品则是使用 Canvas 会多一些。
Canvas Vs DOM
那么为什么 D2C 产品会倾向选择 Canvas,而低代码平台则是更偏向 DOM 方案呢?
接下来会从一些常见的编辑器的侧重点来一一进行分析。
渲染性能
首先从性能入手,为了让同学更好的来了解。
在浏览器窗口内分别使用 Canvas 和 DOM 的绘制方式来插入 1000 个红色方块,最后使用计时代码记录当前的渲染时间。
可以看到 Canvas 的渲染速度比 DOM 是成倍提升的。
下面是两者比对的代码:
<div id="BoxContainer" ></div>
<script>
const container = document.getElementById("BoxContainer");
const startTime = performance.now();
for(let i = 0; i < 1000; i++) {
const square = document.createElement("div");
square.style.width = "10px";
square.style.height = "10px";
square.style.background = "red";
square.style.position = "absolute";
square.style.left = Math.random() * 500 + "px";
square.style.top = Math.random() * 500 + "px";
container.appendChild(square);
}
const endTime = performance.now();
const renderTime = endTime - startTime;
console.log(`DOM render time: ${renderTime} ms`);
</script>
<canvas height="500px" width="500px" id="MyCanvas" ></canvas>
<script>
const canvas = document.getElementById("MyCanvas");
const ctx = canvas.getContext("2d");
const startTime = performance.now();
for(let i = 0; i < 1000; i++) {
ctx.fillStyle = "red";
ctx.fillRect(Math.random() * 500, Math.random() * 500, 10, 10);
}
const endTime = performance.now();
const renderTime = endTime - startTime;
console.log(`Canvas render time: ${renderTime} ms`);
</script>
从渲染的性能上来比,Canvas 无疑是碾压 DOM 的。
事件交互
浏览器 DOM 的优势在于每一个节点都是独立开的,并且具有一套完整易用的浏览器事件系统提供给开发者进行调用,而 Canvas 则是在一个画布平面当中,只能通过元素的 x,y 的距离边界来确定交互的元素,然后通过事件的广播进行操作。
首先:看下 DOM 的事件绑定:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script>
function handleCanvasClick(event) {
console.log('鼠标点击了canvas');
};
</script>
</head>
<body>
<div onclick="handleCanvasClick()" >click</div>
</body>
</html>
然后:下面是 Canvas 的事件绑定:
<canvas id="myCanvas" width="400" height="400"></canvas>
<script>
// 获取canvas元素
var canvas = document.getElementById("myCanvas");
// 获取画布上下文
var ctx = canvas.getContext("2d");
// 绘制一个圆形
ctx.beginPath();
ctx.arc(200, 200, 50, 0, 2 * Math.PI);
ctx.fillStyle = "red";
ctx.fill();
// 添加点击事件监听器
canvas.addEventListener("click", function(event) {
// 获取点击位置的坐标
var x = event.clientX - canvas.offsetLeft;
var y = event.clientY - canvas.offsetTop;
// 判断是否点击了圆形
var distance = Math.sqrt(Math.pow(x-200, 2) + Math.pow(y-200, 2));
if (distance <= 50) {
// 在圆形上方显示鼠标指针的坐标
ctx.fillStyle = "black";
ctx.font = "20px Arial";
ctx.fillText("Clicked at (" + x + ", " + y + ")", x, y - 10);
}
});
</script>
上述示例中,分别用 DOM 和 Canvas 实现了一个点击元素的事件。可以看到,两者的实现难度还是存在很大差异的,DOM 直接使用 onclick 来支持相关的事件绑定,而 Canvas 则是在事件内部通过 event 提供的 x,y 坐标确定点击的内容归属。
选择
通过上述一些简单的示例,可以有一个比较明确的结论,Canvas 渲染器在图形渲染方面性能确实是非常好的,但从开发体验上来看 DOM 会更加简单,不管是添加内容还是事件系统都比 Canvas 方便,学习成本以及上手成本都会低于 Canvas 方案。
蓝湖和即时设计等 D2C 平台绝大部分都是使用 Canvas 作为渲染引擎,其原因是随着设计师上传的素材切图越来越多,如果使用 DOM 来渲染的话,由于节点过多带来的图形渲染的瓶颈会造成使用体验的卡顿,且交互事件并不算太复杂,因此使用 Canvas 能够得到非常好的正向收益。
反观可视化的低代码平台则因为产物是实际应用的原因,不管是现如今 SPA 单页应用还是以前的 HTML 站点都是使用 DOM 来作为页面绘制的主要手段,且页面内容增长远远达不到 D2C 的节点规模的,所以渲染压力相对较小,同时又带有很强的交互逻辑性,物料组件也需要管理和开发,基于以上种种条件下,DOM 自然而然的成为了首选的渲染器绘制方式。
最后就是 Canvas 通常不利于搜索引擎优化(SEO),因为它的内容不易于解析和理解。同时也不支持选择、复制和粘贴等基本的用户界面功能,而 DOM 确很好的支持了这些点。
因此在编辑器渲染技术选型中,需要根据具体的应用场景和需求来选择使用哪种技术:
- 需要高性能的图形和动画效果,不需要 SEO,可以选择 Canvas;
- 需要更好的可维护性和易用性,可以选择 DOM。
总结
在本章节,主要带大家了解 DOM 和 Canvas 在 D2C 和 Lowcode 领域中的一些应用和技术选型的一些细节点。为后续开发物料组件和渲染引擎模块做一些技术积累,为后续开发做一些知识储备。
但由于大部分的公司的组件化基本都是基于 React、Vue 来开发,在接入低代码平台中的物料中心的时候,采用 DOM 的方案可以节约大量的改造成本,使用过渡也会更为平滑。
所以最终我们可视化搭建的设计器也将选择 DOM 作为搭建技术方案,至于在设计器中存在大量组件渲染卡顿的情况,在本章开头也提到了,除了基础的原生技术方案有区别之外,还可以通过一些额外的研发设计方案来规避,例如数据组装与视图渲染分离等来解决性能问题,这些具体的优化措施我们将放在搭建实战篇进行更多的细节讲解。
参考
- The Future Web: Will Canvas Rendering Replace the DOM?
- www.youtube.com/watch?v=Swp…
- Google Docs is switching to canvas-based rendering. Here's what that means.
写在最后
如果你有什么疑问或者更好的建议,欢迎在评论区提出。 👏
4 架构:Canvas VS DOM