平臺:designable設計器
github:designable
目錄
- 1 背景
- 2 技術棧
- 3 組件拖拽和放置
- 3.1 類型定義
- 3.2 拖拽
- 3.3 放置
1 背景
由于業務需求,我們需要實現designable平臺的一個簡易版的組件拖拽功能。
功能列表:
- 拖拽區域
- 渲染組件列表,包括組件的名稱和icon
- 組件可以拖動
- 放置區域
- 拖動后的組件可以放置,并且放置區域的組件依舊存在
- 放置區域的組件可以正確渲染相應樣式,使用formily的schema json渲染
- 放置區域的組件可以上下移動排序,同時可以進行刪除和編輯操作
2 技術棧
antd
formily:表單引擎,可以根據schema json直接渲染表單
react-beautiful-dnd:常用于列表的拖拽,支持排序
react-dnd:拖拽和放置功能,比如上面截圖的組件拖拽
3 組件拖拽和放置
3.1 類型定義
右側組件類型:id唯一標識,scheme存放渲染表單的json文件
export interface ComponentConfig {id?: string; // 唯一標識,隨機生成,且不可更改key: string; // 表單字段key,用戶可以更改title: string; // 拖拽區域的文案,不可更改component_type: ComponentType; // RN側的組件標識,不可更改schema: ISchema;
}export enum ComponentType {TextInputRow = 'TextInputRow', // 文本輸入框DateInputRow = 'DateInputRow', // 時間選擇器CheckBox = 'CheckBox',
}
右側組件列表:
export const ComponentConfigs: ComponentConfig[] = [{key: ComponentType.TextInputRow,schema: {title: ComponentType.TextInputRow,type: 'string','x-component': 'Input','x-decorator': 'FormItem','x-rn-component': ComponentType.TextInputRow, // RN側的組件名稱,必須要保持一致},},{key: ComponentType.DateInputRow,schema: {title: ComponentType.DateInputRow,type: 'string','x-component': 'DatePicker','x-decorator': 'FormItem','x-rn-component': ComponentType.DateInputRow,},},{key: ComponentType.CheckBox,schema: {title: ComponentType.CheckBox,type: 'string','x-component': 'Checkbox','x-decorator': 'FormItem','x-rn-component': ComponentType.CheckBox,},},
].map((i) => ({ ...i, title: i.key, component_type: i.key }));
3.2 拖拽
useDrag
:讓DOM實現拖拽能力的構子
- 請求參數:
type
: 指定元素的類型,只有 類型相同的元素 才能進行drop操作item
: 元素在拖拽過程中,描述該對象的數據。可以在useDrop
中的drop
接收到該數據collect
: 返回一個描述狀態的普通對象,然后返回以注入到組件中。它接收兩個參數,一個DragTargetMonitor
實例和拖拽元素描述信息item
- 返回參數:
- 第一個返回值:是一個對象 表示關聯在拖拽過程中的變量,需要在傳入
useDrag
的規范方法的collect
屬性中進行映射綁定, 比如:isDraging
,canDrag
等 - 第二個返回值: 代表拖拽元素的ref
- 第三個返回值: 代表拖拽元素拖拽后實際操作到的dom
- 第一個返回值:是一個對象 表示關聯在拖拽過程中的變量,需要在傳入
// 用于包裹每一個可以拖拽的組件
export const WrapComponent = (props: DndComponentDndItem) => {const [, drag] = useDrag(() => ({type: ItemTypes.CARD,item: props.config,// collect中可以監控drag狀態變更,并把狀態暴露給組件collect: (monitor) => ({ isDragging: !!monitor.isDragging() }),}));return (<divstyle={{width: 100, // todo: 卡片無法居中cursor: 'move',height: 50,display: 'flex',justifyContent: 'center',alignItems: 'center',backgroundColor: 'white',borderRadius: 4,}}ref={drag} // dom元素實例>{props.children}</div>);
};
3.3 放置
useDrop
:讓拖拽物放置的構子
- 請求參數:
type
: 指定元素的類型,只有 類型相同的元素 才能進行drop操作item
: 元素在拖拽過程中,描述該對象的數據。可以在useDrop
中的drop
接收到該數據collect
: 返回一個描述狀態的普通對象,然后返回以注入到組件中。它接收兩個參數,一個DragTargetMonitor
實例和拖拽元素描述信息item
- 返回參數:
- 第一個返回值:是一個對象 表示關聯在拖拽過程中的變量,需要在傳入
useDrag
的規范方法的collect
屬性中進行映射綁定, 比如:isDraging
,canDrag
等 - 第二個返回值: 代表拖拽元素的ref
- 第三個返回值: 代表拖拽元素拖拽后實際操作到的dom
- 第一個返回值:是一個對象 表示關聯在拖拽過程中的變量,需要在傳入