本文仅为总结技术点,阅读需要中高的前端基础、和一定的低代码基础
编辑平台划分
- header:工具栏
- material:物料区
- stage:编辑区
- setting:属性设置区
区域之间的滑动
使用allotment
实现各区域的resize。
pnpm i allotment
协议-数据结构
低代码平台目的是实现页面的配置式生成
产物是现代前端界面
所以可以用html
元素的结构来定义协议,亦可从react
的jsx
思想受到启发。
v1.0
协议:
//src/types/component/component.d.ts
export interface ComponentV1 {
id: string | number
name: string
type: COMPONENT_TYPE_ENUM
props: Record<string, any>
children?: ComponentV1[] | ComponentV1
}
//src/types/component/componentMap.ts
export enum COMPONENT_TYPE_ENUM {
BUTTON = 'button',
TEXT = 'text',
SPACE = 'space'
}
export const COMPONENTS_SET: Set<COMPONENT_TYPE_ENUM> = new Set([
...Object.values(COMPONENT_TYPE_ENUM)
])
渲染
只能渲染原生
mock
协议的component
数据,进行渲染:
//src/core/stage/render.tsx
import { ComponentV1 } from '@/types/component/component'
import { COMPONENTS_SET } from '@/types/component/componentMap'
import React, { ReactNode } from 'react'
export const render = (component: ComponentV1): ReactNode => {
const { type, props, children } = component
if (!COMPONENTS_SET.has(type)) return null
if (children) {
const childNodes = Array.isArray(children)
? children.map((c) => render(c))
: render(children)
return React.createElement(type, props, childNodes)
} else {
return React.createElement(type, props)
}
}
渲染效果:
渲染组件库
通过协议的type
,枚举出原生和antd
组件来进行渲染,渲染到指定组件库:
export type NativeComponentType = BoxComponentProps
export type AntdComponentType = ButtonComponentProps | TypographyComponentProps
export type AllComponentType = NativeComponentType | AntdComponentType
export enum ANTD_COMPONENT_ENUM {
BUTTON = 'Button',
TYPOGRAPHY = 'Typography'
}
export enum NATIVE_COMPONENT_ENUM {
BOX = 'div'
}
const isNativeComponent = (type: any) => {
return Object.values(NATIVE_COMPONENT_ENUM).includes(type)
}
const isAntdComponent = (type: any) => {
return Object.values(ANTD_COMPONENT_ENUM).includes(type)
}
export const render = (component: AllComponentType): ReactNode => {
const { type } = component
if (isNativeComponent(type)) {
return renderNativeComponent(component as NativeComponentType)
} else if (isAntdComponent(type)) {
return renderAntdComponent(component as AntdComponentType)
} else {
return null
}
}
const renderNativeComponent = (component: NativeComponentType) => {
const { type } = component
switch (type) {
case NATIVE_COMPONENT_ENUM.BOX: {
const { props } = component as BoxComponentProps
const { children, ...otherProps } = props
const childNode = children.map((c) => render(c))
return React.createElement('div', otherProps, childNode)
}
default:
return null
}
}
const renderAntdComponent = (component: AntdComponentType): ReactNode => {
const { type } = component
switch (type) {
case ANTD_COMPONENT_ENUM.BUTTON: {
const { props } = component as ButtonComponentProps
return <Button {...props}></Button>
}
case ANTD_COMPONENT_ENUM.TYPOGRAPHY: {
const { props } = component as TypographyComponentProps
return <Typography {...(props as any)} />
}
default:
return null
}
}