低代码平台技术点 - 2

135 阅读1分钟

本文仅为总结技术点,阅读需要中高的前端基础、和一定的低代码基础

编辑平台划分

  • header:工具栏
  • material:物料区
  • stage:编辑区
  • setting:属性设置区

区域之间的滑动

使用allotment实现各区域的resize。

pnpm i allotment

协议-数据结构

低代码平台目的是实现页面的配置式生成

产物是现代前端界面

所以可以用html元素的结构来定义协议,亦可从reactjsx思想受到启发。

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)
  }
}

渲染效果:

image.png

渲染组件库

通过协议的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
  }
}

image.png