对这个系列感兴趣的可以关注订阅专栏:从零开始打造一个低代码平台
前言
前面一章我们引入了图标资源,添加了第一个控件,实现了将控件拖拽到画布的事件框架。这一章我们将继续完成整个功能,将控件拖拽到画布上后生一个Button组件。
一、控件和组件
我们先厘清一下控件
和组件
的概念。控件
是WidgetBar
上的元素(Widget
),组件
是在画布上创建出来的元素(Component
),控件是组件的类别,某种控件可以创建出多个组件。例如,拖拽WidgetBar
上的Button控件可以在画布上创建多个Button组件。
二、定义组件
我们定义一下组件类型,一个最简单的组件包含类型,位置和尺寸信息。以下是组件类型定义:
interface Widget {
type: string;
left: number;
top: number;
width: number;
height: number;
}
然后在Canvas
里定义一个widgets
:
const [widgets, setWidgets] = useState<Widget>([]);
Canvas
负责绘出列表里所有的组件:
<div className={className ?? ""}>
{widgets.map((widget, index) => {
return (
<div
key={index}
className="absolute bg-gray-700 rounded-md flex justify-center items-center"
style={{
left: `${widget.left}px`,
top: `${widget.top}px`,
width: `${widget.width}px`,
height: `${widget.height}px`,
}}
>
<i>Button</i>
</div>
);
})}
</div>
三、拖拽事件
前一章提到,需要在source
元素上实现onDragStart
事件,在这里将控件类型等相关信息打包送出,然后在target
元素上实现onDrop
,接受数据,然后根据控件类型等信息创建组件。
目前我们只定义了一种控件,所以我们先偷点懒,省掉onDragStart
打包数据的步骤,直接处理onDrop
,在onDrop
里新增一个组件。
onDrop={(e) => {
const { clientX, clientY } = e;
setWidgets([
...widgets,
{ type: "btn", left: clientX, top: clientY, width: 100, height: 50 },
]);
}}
四、完整的Canvas组件
改造后的完整Canvas
如下:
import { useState } from "react";
interface CanvasProps {
className?: string;
}
export const Canvas: React.FC<CanvasProps> = ({ className }) => {
const [widgets, setWidgets] = useState<
{ type: string; left: number; top: number; width: number; height: number }[]
>([]);
return (
<div
className={className ?? ""}
onDragOver={(e) => {
e.preventDefault();
}}
onDrop={(e) => {
const { clientX, clientY } = e;
setWidgets([
...widgets,
{ type: "btn", left: clientX, top: clientY, width: 100, height: 50 },
]);
}}
>
{widgets.map((widget, index) => {
return (
<div
key={index}
className="absolute bg-gray-700 rounded-md flex justify-center items-center"
style={{
left: `${widget.left}px`,
top: `${widget.top}px`,
width: `${widget.width}px`,
height: `${widget.height}px`,
}}
>
<i>Button</i>
</div>
);
})}
</div>
);
};
现在我们可以从WidgetBar
将Button控件拖拽到Canvas
上,创建多个的Button组件了。如下图所示:
但有个小问题,组件生成的位置跟鼠标的位置不一样,似乎有固定的偏差。这个问题我们在后续章节讲组件定位的时候会来解决。
总结
这个章节跟上个章节我们实现了组件的拖拽,一个可视化平台基本又核心的功能。当然,产品化的实现还要考虑很多其它的问题,但我们好歹算开始了我们的第一个功能设计。