前言
前一章我们开始引入了全局状态管理,扩展了侧边栏显示屏幕列表,但拖拽到屏幕的组件还没有同步用全局数据。这一章我们把相关的地方都同步用全局数据来管理,实现屏幕切换,还要继续扩展WidgetBar
。
一、扩展控件
前面章节里的WidgetBar
只有一个Button
,所以我们偷了点懒,在Canvas
绘制组件的时候直接写死了Button
。在实际产品里当然不能这么做了,接下来我们进一步扩展控件和WidgetBar
,让它看起来更产品化。
我们已经定义了Button
和Container
的数据类型,但对应的控件我们还没有定义。先来完成它们的外观。
// Button Widget
import {
WidgetProps } from '.';
export const ButtonWidget: React.FC<WidgetProps> = ({
className,
left,
top,
width,
height,
}) => {
return (
<div
className={
`absolute left-3 top-3 w-12 bg-gray-700 rounded-md flex flex-col justify-center items-center p-2 space-y-2 ${
className ?? ""
}`}
style={
{
left, top, width, height }}
>
Button
</div>
);
};
// Container Widget
import {
WidgetProps } from '.';
export const ContainerWidget: React.FC<WidgetProps> = ({
className, left, top, width, height }) => {
return (
<div
className={
`absolute left-3 top-3 w-12 bg-gray-700 rounded-md flex flex-col justify-center items-center p-2 space-y-2 ${
className?? ""
}`}
style={
{
left, top, width, height
}}
>Container</div>
);
};
嗯?这两个控件有什么差别吗?本质上没差别,就是一个普通的<div>
,但对于系统来说就是两个控件,这就够了。至于它们的具体实现不是这一章节的主要内容,我们留待日后再表。
二、定义控件库
上面定义好了Button
和Container
控件,我们还要把控件的数据类型跟对应的控件映射起来,这样我们可以根据组件的控件类型绘出相应的组件。
import {
ButtonWidget } from './btn-widget';
import {
ContainerWidget } from './cont-widget';
export interface WidgetProps {
className?: string;
}
interface WidgetLib {
[key: string]: {
icon: string, widget: React.FC<WidgetProps> };
}
export const widgetLib: WidgetLib = {
btn: {
icon: 'icon-anniu', widget: ButtonWidget },
cont: {
icon: 'icon-rongqi', widget: ContainerWidget },
}
WidgetLib
是一个Map类型,key
是控件名称,对应控件数据里的type
,这里我把Button
的控件数据再列出来对比看下:
export interface Button extends Widget {
type: 'btn'; // 对应`WidgetLib`里的`key`
text: string; // `Button`的属性
}
好,这样我们就定义好了控件数据,控件外观和它们的映射关系。
二、扩展WidgetStore
前面我们只在WidgetStore
里定义了AddScr
和RemoveScr
用来添加/删除屏幕,现在我们要增加一个AddWidget
,当拖拽控件到画布上时,通过AddWidget
来添加一个组件到当前的屏幕里。另外,我们增加currScrId
用来标记当前处于哪个屏幕,和setCurrScrId
来变更当前的屏幕,当用户点击不同屏幕时做切换。对了,还有一个init
用作初始化操作,谁家还没个初始化呢。如