低代码与搭建平台

What — 什么是低代码与搭建平台

基本定义

概念定义典型用户
No-code(零代码)纯可视化配置,零编码完成应用搭建业务人员、运营人员
Low-code(低代码)可视化拖拽为主,少量编码扩展逻辑前端开发者、全栈开发者
Pro-code(纯代码)传统手写代码开发专业开发者

三者并非泾渭分明,而是一个连续光谱:

No-code ◄────────────────────► Low-code ◄────────────────────► Pro-code
  纯配置                        拖拽 + 少量代码                  全量手写
  灵活度低                      灵活度中等                      灵活度高
  上手门槛低                    上手门槛中等                    上手门槛高

核心概念

概念说明
组件库(Component Library)可拖拽的基础物料,如按钮、表格、表单、图表等
属性面板(Property Panel / Setter)编辑组件属性的表单面板,如尺寸、颜色、数据源绑定
画布(Canvas)所见即所得的拖拽编排区域
渲染器(Renderer)将 Schema 渲染为真实 DOM 的引擎
数据源绑定(Data Binding)将组件属性与变量 / API 响应绑定,实现动态数据驱动
逻辑编排(Logic Orchestration)可视化编写事件流 / 逻辑流,替代手写事件处理
模板市场(Template Marketplace)预制页面 / 区块模板,一键创建应用

整体架构

┌──────────────────────────────────────────────────────┐
│                     Editor(编辑器)                   │
│  ┌──────────┐  ┌──────────┐  ┌────────────────────┐  │
│  │ 组件面板  │  │ 属性面板  │  │    画布 Canvas      │  │
│  │ Palette  │  │ Setter   │  │  (实时预览 + 拖拽)  │  │
│  └──────────┘  └──────────┘  └────────────────────┘  │
│                        │                              │
│                   Schema (JSON)                       │
│                        │                              │
├────────────────────────┼──────────────────────────────┤
│                   Renderer(渲染器)                    │
│         Schema ──► 递归解析 ──► 动态组件 ──► DOM       │
├──────────────────────────────────────────────────────┤
│                    Server(服务端)                     │
│         Schema 存储 │ 版本管理 │ 发布 │ 权限           │
└──────────────────────────────────────────────────────┘

核心数据流:Editor 产出 Schema → Renderer 消费 Schema → 渲染页面


Why — 为什么需要低代码与搭建平台

技术方案对比

维度Low-codePro-codeNo-codeCMS
开发效率高(拖拽 + 少量代码)低(全量手写)极高(纯配置)中(内容配置)
灵活度中高极高
学习门槛
可维护性依赖平台完全可控依赖平台依赖平台
性能上限受 Schema 渲染开销限制可极致优化受平台限制一般
适用场景中后台、营销页所有场景简单表单 / 问卷内容展示
团队协作天然支持需额外方案天然支持天然支持
可移植性低(平台绑定)极低(平台绑定)

知名平台

平台类型特点
钉钉宜搭Low-code阿里出品,钉钉生态深度集成
腾讯微搭Low-code腾讯云生态,小程序支持
阿里低代码引擎(lowcode-engine)引擎开源,可二次开发,生态丰富
Amis(百度)JSON-DrivenJSON Schema 驱动 UI,前端零代码
RetoolLow-code内部工具搭建,数据库直连
AppsmithLow-code开源,JS 扩展,数据源丰富
BubbleNo-code全栈零代码,数据库 + 逻辑 + UI

适用场景

  • 内部工具 / 中后台系统:CRUD 密集,重复度高,低代码可大幅提效
  • 管理后台:表格 + 表单 + 筛选,低代码几乎全覆盖
  • 表单 / 问卷:逻辑简单,配置化天然匹配
  • 营销落地页:活动频繁、页面结构趋同,模板化搭建
  • 数据看板:图表组合,数据源绑定即可

何时不宜使用低代码

场景原因
高交互复杂度应用(游戏、3D 编辑器)Schema 难以描述复杂交互
极致性能要求页面Schema 解析 + 动态组件有运行时开销
高度定制化 UI受限于组件库能力
核心业务逻辑复杂逻辑编排可读性差,调试困难
需要长期维护的核心产品平台绑定风险,迁移成本高

How — 如何实现低代码与搭建平台

1. Schema 设计

Schema 是低代码平台的核心数据结构,描述页面的完整结构。

{
  "schemaVersion": "1.0.0",
  "page": {
    "id": "page_001",
    "type": "Page",
    "props": {
      "title": "用户管理",
      "layout": "vertical"
    },
    "children": [
      {
        "id": "form_001",
        "type": "Form",
        "props": {
          "layout": "horizontal",
          "labelWidth": 80
        },
        "children": [
          {
            "id": "input_001",
            "type": "Input",
            "props": {
              "label": "用户名",
              "placeholder": "请输入用户名"
            },
            "bindings": {
              "value": "{{formData.username}}"
            },
            "events": {
              "onChange": {
                "type": "setState",
                "params": {
                  "key": "formData.username",
                  "value": "$event.value"
                }
              }
            }
          }
        ]
      }
    ],
    "state": {
      "formData": {
        "username": ""
      }
    },
    "dataSources": [
      {
        "id": "ds_users",
        "type": "api",
        "options": {
          "url": "/api/users",
          "method": "GET"
        },
        "autoFetch": true
      }
    ]
  }
}

Schema 设计要点:

要点说明
组件树结构children 嵌套描述组件层级
属性描述props 存放组件静态属性
数据绑定bindings 描述动态表达式绑定
事件绑定events 描述事件触发动作
状态管理state 定义页面级状态变量
数据源dataSources 描述 API / 数据库连接
版本号schemaVersion 保证向后兼容

2. 编辑器实现

拖拽引擎

推荐使用 dnd-kit(React)或 SortableJS(框架无关):

// 基于 dnd-kit 的拖拽画布实现
import { DndContext, DragOverlay, closestCenter } from '@dnd-kit/core';
import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';

function EditorCanvas({ schema, onMoveComponent }: CanvasProps) {
  const sensors = useSensors(
    useSensor(PointerSensor, { activationConstraint: { distance: 5 } })
  );

  function handleDragEnd(event: DragEndEvent) {
    const { active, over } = event;
    if (over && active.id !== over.id) {
      onMoveComponent(active.id as string, over.id as string);
    }
  }

  return (
    <DndContext
      sensors={sensors}
      collisionDetection={closestCenter}
      onDragEnd={handleDragEnd}
    >
      <SortableContext
        items={schema.children.map(c => c.id)}
        strategy={verticalListSortingStrategy}
      >
        {schema.children.map(child => (
          <SortableComponentNode key={child.id} node={child} />
        ))}
      </SortableContext>
      <DragOverlay>
        {/* 拖拽预览层 */}
      </DragOverlay>
    </DndContext>
  );
}

属性面板(Setter)

属性面板本质是 Schema 驱动的表单,推荐使用 formily

// Setter 面板 — 根据组件 PropertySchema 动态生成表单
import { SchemaField } from '@formily/react';
import { createSchemaField } from '@formily/react';

const SchemaField = createSchemaField({
  components: {
    Input,
    Select,
    ColorPicker,
    NumberInput,
    Switch,
    JsonEditor,
  },
});

function PropertyPanel({ componentSchema, onChange }: PropertyPanelProps) {
  const formSchema = {
    type: 'object',
    properties: transformPropSchemaToFormily(componentSchema.propertySchema),
  };

  return (
    <FormProvider form={form}>
      <SchemaField schema={formSchema} />
    </FormProvider>
  );
}

画布实时预览

// 画布 — 实时渲染 + 交互拦截
function Canvas({ schema }: { schema: PageSchema }) {
  return (
    <div className="canvas-container">
      <Renderer schema={schema} mode="edit" />
    </div>
  );
}

// 编辑模式下拦截组件事件,阻止默认行为
function EditableWrapper({ children, nodeId, isSelected }: EditableWrapperProps) {
  return (
    <div
      className={`editable-wrapper ${isSelected ? 'selected' : ''}`}
      onClick={(e) => {
        e.stopPropagation();
        selectNode(nodeId);
      }}
    >
      {children}
      {isSelected && <ResizeHandles nodeId={nodeId} />}
    </div>
  );
}

3. 渲染器(Renderer)

渲染器是低代码平台的核心运行时:Schema → 递归解析 → 动态组件 → DOM

// Schema 驱动的递归渲染器
import React, { Suspense, lazy } from 'react';

// 组件注册表
const componentMap: Record<string, React.ComponentType<any>> = {};

function registerComponent(name: string, component: React.ComponentType<any>) {
  componentMap[name] = component;
}

// 动态加载组件
function resolveComponent(type: string): React.ComponentType<any> | null {
  return componentMap[type] ?? null;
}

// 递归渲染节点
function renderNode(node: ComponentSchema, context: RenderContext): React.ReactNode {
  const Component = resolveComponent(node.type);
  if (!Component) {
    console.warn(`Unknown component type: ${node.type}`);
    return null;
  }

  // 解析绑定表达式
  const resolvedProps = resolveBindings(node.props, node.bindings, context);

  // 解析事件
  const resolvedEvents = resolveEvents(node.events, context);

  return (
    <Component key={node.id} {...resolvedProps} {...resolvedEvents}>
      {node.children?.map(child => renderNode(child, context))}
    </Component>
  );
}

// 页面级渲染入口
function Renderer({ schema, mode = 'prod' }: RendererProps) {
  const context = usePageContext(schema);

  return (
    <PageProvider context={context}>
      {renderNode(schema.page, context)}
    </PageProvider>
  );
}

渲染器性能优化:

优化手段说明
组件懒加载React.lazy + Suspense 按需加载组件
虚拟渲染大列表只渲染可视区域组件节点
增量更新Schema diff 后只更新变化的子树
缓存组件实例React.memo 避免无变化子树重渲染
编译时优化将 Schema 预编译为渲染函数(如阿里 lowcode-engine 的 simulator)

4. 数据源绑定

// 变量系统与数据流
interface PageState {
  [key: string]: any;
}

// 表达式解析 — 使用 {{ }} 语法
function evaluateExpression(expr: string, context: PageState): any {
  // 例如 "{{formData.username}}" → context.formData.username
  const match = expr.match(/^\{\{(.+)\}\}$/);
  if (!match) return expr;

  try {
    const fn = new Function('state', `with(state) { return ${match[1]}; }`);
    return fn(context);
  } catch (e) {
    console.warn(`Expression evaluation failed: ${expr}`, e);
    return undefined;
  }
}

// 数据源管理
function useDataSource(configs: DataSourceConfig[], state: PageState) {
  const [dataMap, setDataMap] = useState<Record<string, any>>({});
  const [loadingMap, setLoadingMap] = useState<Record<string, boolean>>({});

  useEffect(() => {
    configs.forEach(async (ds) => {
      if (ds.autoFetch) {
        setLoadingMap(prev => ({ ...prev, [ds.id]: true }));
        const data = await fetchDataSource(ds);
        setDataMap(prev => ({ ...prev, [ds.id]: data }));
        setLoadingMap(prev => ({ ...prev, [ds.id]: false }));
      }
    });
  }, [configs]);

  return { dataMap, loadingMap, refetch: (id: string) => { /* ... */ } };
}

5. 逻辑 / 事件编排

可视化逻辑编排采用节点流(Node-based)方式:

{
  "logicFlows": [
    {
      "id": "flow_submit",
      "name": "提交表单",
      "trigger": { "type": "event", "source": "btn_submit", "event": "onClick" },
      "steps": [
        {
          "id": "step_validate",
          "type": "validate",
          "params": { "formId": "form_001" }
        },
        {
          "id": "step_api",
          "type": "callApi",
          "params": {
            "dataSourceId": "ds_create_user",
            "body": "{{formData}}"
          },
          "condition": "{{step_validate.valid === true}}"
        },
        {
          "id": "step_notify",
          "type": "showMessage",
          "params": {
            "type": "success",
            "content": "提交成功"
          },
          "condition": "{{step_api.success === true}}"
        }
      ]
    }
  ]
}

动作系统(Action System):

动作类型说明
setState更新页面状态变量
callApi调用数据源 API
navigate页面跳转
showMessage显示提示消息
validate表单校验
openDialog打开弹窗
download文件下载
customJs执行自定义 JS 代码

6. 阿里低代码引擎(lowcode-engine)

阿里低代码引擎是阿里开源的低代码搭建基础架构,提供编辑器框架与渲染器。

核心概念:

概念说明
Editor编辑器实例,管理面板、插件、设置器
DocumentModel文档模型,对应一个页面的 Schema 树
NodeSchema 树节点,对应一个组件实例
Prop节点属性,支持表达式 / JSExpression
SettingField设置器字段,描述属性编辑方式
ComponentMeta组件元信息,描述组件的 props / snippets / 配置
Plugin插件,扩展编辑器功能
Setter属性设置器,如 StringSetter / ColorSetter
Simulator模拟器,在 iframe 中渲染画布实现隔离

架构概览:

┌─────────────────────────────────────────────────┐
│              lowcode-editor(编辑器壳)            │
│  ┌──────────┐ ┌──────────┐ ┌─────────────────┐  │
│  │ 左侧面板  │ │  画布区   │ │   右侧设置面板   │  │
│  │ Outline  │ │Simulator │ │   Settings      │  │
│  │ Component│ │  (iframe) │ │   Props/Style   │  │
│  └──────────┘ └──────────┘ └─────────────────┘  │
│                       │                          │
│              DocumentModel (Schema Tree)          │
│                       │                          │
│  ┌────────────────────┼────────────────────────┐ │
│  │           Plugin System                      │ │
│  │  PluginA  PluginB  PluginC  ...             │ │
│  └──────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘

组件描述(meta):

{
  "componentName": "Button",
  "title": "按钮",
  "docUrl": "",
  "screenshot": "",
  "devMode": "proCode",
  "tags": ["通用"],
  "props": [
    {
      "name": "type",
      "propType": "oneOf",
      "defaultValue": "primary",
      "setter": {
        "componentName": "SelectSetter",
        "props": {
          "options": [
            { "label": "主要", "value": "primary" },
            { "label": "默认", "value": "default" },
            { "label": "危险", "value": "danger" }
          ]
        }
      }
    }
  ],
  "snippets": [
    {
      "title": "主要按钮",
      "screenshot": "",
      "schema": {
        "componentName": "Button",
        "props": { "type": "primary", "children": "按钮" }
      }
    }
  ]
}

7. Amis(百度)

Amis 是百度开源的 JSON 驱动 UI 框架,通过 JSON Schema 描述页面,无需前端代码。

核心思路:JSON 即页面。

{
  "type": "page",
  "title": "用户管理",
  "body": {
    "type": "crud",
    "api": "/api/users",
    "columns": [
      { "name": "id", "label": "ID" },
      { "name": "name", "label": "姓名" },
      { "name": "email", "label": "邮箱" },
      {
        "type": "operation",
        "label": "操作",
        "buttons": [
          {
            "type": "button",
            "label": "编辑",
            "actionType": "dialog",
            "dialog": {
              "title": "编辑用户",
              "body": {
                "type": "form",
                "api": "PUT:/api/users/${id}",
                "body": [
                  { "type": "input-text", "name": "name", "label": "姓名" },
                  { "type": "input-email", "name": "email", "label": "邮箱" }
                ]
              }
            }
          },
          {
            "type": "button",
            "label": "删除",
            "actionType": "ajax",
            "confirmText": "确认删除?",
            "api": "DELETE:/api/users/${id}"
          }
        ]
      }
    ]
  }
}

Amis 特点:

特点说明
JSON 驱动纯 JSON 即可描述完整页面
内置丰富组件CRUD、Form、Chart、Wizard 等 100+ 组件
API 对接声明式 API 配置,自动发请求、自动渲染
表达式${xxx} 模板语法,支持条件渲染
扩展可注册自定义组件
无编辑器原生不提供拖拽编辑器,需搭配搭建平台

8. 模板系统

{
  "templates": [
    {
      "id": "tpl_admin_dashboard",
      "name": "管理后台看板",
      "category": "中后台",
      "thumbnail": "/thumbnails/admin-dashboard.png",
      "schema": { /* 完整页面 Schema */ },
      "blocks": [
        {
          "id": "blk_stat_cards",
          "name": "统计卡片行",
          "slot": "header",
          "schema": { /* 区块 Schema */ }
        },
        {
          "id": "blk_data_table",
          "name": "数据表格",
          "slot": "body",
          "schema": { /* 区块 Schema */ }
        }
      ]
    }
  ]
}

模板机制:

  • 页面模板:完整页面 Schema,一键创建
  • 区块模板(Block):可复用的页面局部,拖入画布
  • 另存为模板:用户可将已搭建的页面 / 区块保存为模板
  • 模板市场:团队共享模板库,分类浏览

9. 版本管理与发布

{
  "schemaId": "page_001",
  "versions": [
    {
      "version": "1.0.0",
      "schema": { /* ... */ },
      "createdAt": "2026-01-01T00:00:00Z",
      "publishedAt": "2026-01-02T00:00:00Z",
      "status": "published"
    },
    {
      "version": "1.1.0",
      "schema": { /* ... */ },
      "createdAt": "2026-03-01T00:00:00Z",
      "publishedAt": null,
      "status": "draft"
    }
  ],
  "publishConfig": {
    "abTesting": {
      "enabled": true,
      "variantA": "1.0.0",
      "variantB": "1.1.0",
      "ratio": 0.5
    }
  }
}
能力说明
Schema 版本化每次保存生成新版本,可追溯
回滚一键回滚至任意历史版本
草稿 / 发布草稿态独立于线上版本
A/B 测试不同版本按比例分流

10. 扩展机制

自定义组件注册

// 注册自定义组件到低代码平台
import { registerComponent } from '@lowcode/runtime';

const CustomChart: React.FC<CustomChartProps> = ({ data, chartType, title }) => {
  // 自定义图表实现
  return <div className="custom-chart">{/* ... */}</div>;
};

// 注册组件 + 元信息
registerComponent('CustomChart', {
  component: CustomChart,
  meta: {
    title: '自定义图表',
    group: '数据展示',
    icon: 'chart',
    props: [
      { name: 'chartType', type: 'string', setter: 'SelectSetter', options: ['bar', 'line', 'pie'] },
      { name: 'data', type: 'array', setter: 'JsonSetter' },
    ],
    snippets: [
      {
        title: '柱状图',
        schema: { type: 'CustomChart', props: { chartType: 'bar' } },
      },
    ],
  },
});

自定义 Setter

// 自定义属性设置器
import { registerSetter } from '@lowcode/editor';

function ColorGradientSetter({ value, onChange }: SetterProps) {
  return (
    <div className="color-gradient-setter">
      <ColorPicker value={value?.from} onChange={c => onChange({ ...value, from: c })} />
      <span>→</span>
      <ColorPicker value={value?.to} onChange={c => onChange({ ...value, to: c })} />
    </div>
  );
}

registerSetter('ColorGradientSetter', ColorGradientSetter);

插件系统

// 编辑器插件
import { ILowCodePluginContext } from '@lowcode/editor';

const MyPlugin = (ctx: ILowCodePluginContext) => ({
  name: 'MyPlugin',
  init() {
    // 注册自定义面板
    ctx.workspace.addPanel({
      name: 'AIAssistant',
      area: 'left',
      content: <AIAssistantPanel />,
    });
    // 注册快捷键
    ctx.hotkey.bind('cmd+s', () => ctx.project.save());
  },
  destroy() { /* 清理 */ },
});

11. 安全

XSS 防护

// Schema 中的 XSS 防护 — 禁止 dangerouslySetInnerHTML 直接注入
function sanitizeSchema(schema: ComponentSchema): ComponentSchema {
  const sanitized = cloneDeep(schema);

  function walk(node: ComponentSchema) {
    // 过滤危险属性
    if (node.props?.dangerouslySetInnerHTML) {
      const html = node.props.dangerouslySetInnerHTML.__html;
      node.props.dangerouslySetInnerHTML = {
        __html: DOMPurify.sanitize(html, {
          ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'br', 'p'],
          ALLOWED_ATTR: ['href', 'target'],
        }),
      };
    }
    node.children?.forEach(walk);
  }

  walk(sanitized);
  return sanitized;
}

表达式沙箱

// 安全的表达式执行沙箱
function createSandbox() {
  const blockedGlobals = [
    'window', 'document', 'globalThis', 'self',
    'fetch', 'XMLHttpRequest', 'importScripts',
    'WebSocket', 'eval', 'Function',
  ];

  return {
    evaluate(expr: string, context: Record<string, any>): any {
      // 白名单模式:只允许访问 context 中定义的变量
      const sandboxProxy = new Proxy(context, {
        has: () => true, // 拦截 with 作用域查找
        get: (target, key) => {
          if (blockedGlobals.includes(key as string)) return undefined;
          return target[key as string];
        },
      });

      try {
        const fn = new Function('state', `with(state) { return (${expr}); }`);
        return fn(sandboxProxy);
      } catch {
        return undefined;
      }
    },
  };
}

权限控制

层级控制项
编辑器谁能编辑 / 查看 / 发布页面
组件哪些组件对哪些角色可见
数据源API 调用权限校验
表达式限制可访问的上下文变量
导出Schema 导出 / 导入权限

常见陷阱

#陷阱说明解决方案
1Schema 无限嵌套导致渲染栈溢出组件树层级过深或循环引用渲染时设置最大深度限制(如 50 层),Schema 校验时检测循环引用
2表达式 eval 直接执行用户输入存在 XSS / 代码注入风险使用沙箱执行,白名单变量访问
3画布拖拽性能卡顿节点数过多时每次拖拽全量重渲染虚拟化渲染,只渲染可视区域节点;增量更新
4组件注册名冲突不同组件库注册相同 componentName使用命名空间前缀,如 Basic.Button / Chart.Button
5Schema 版本不兼容升级 Schema 后旧版本无法渲染版本号管理 + 迁移脚本(migration)
6编辑器状态与 Schema 不同步拖拽 / 属性修改后 Schema 未及时更新单一数据源原则,所有操作通过 command 修改 Schema
7自定义组件无法响应 Schema 变更组件未正确声明 props 依赖组件注册时声明 propsMeta,渲染器依据 props diff 判断是否重渲染
8数据源请求未做竞态处理快速切换页面时旧请求覆盖新数据请求加版本号 / AbortController 取消旧请求
9逻辑编排难以调试可视化逻辑流出错时无法断点调试提供逻辑执行日志面板,支持逐步回放
10模板与组件版本耦合模板引用的组件升级后模板失效模板记录组件版本范围,渲染时做兼容性检查

最佳实践

  • Schema 优先:所有页面结构、属性、事件均通过 Schema 描述,编辑器只是 Schema 的可视化操作界面
  • 单一数据源:编辑器中 Schema 是唯一真相来源,避免多处状态不一致
  • 增量更新:渲染器通过 Schema diff 实现局部更新,避免全量重渲染
  • 组件元信息完备:每个组件提供完整的 meta(属性定义 / 默认值 / 设置器 / 快捷片段),编辑器据此生成面板
  • 沙箱执行表达式:所有用户输入的表达式在沙箱中运行,禁止访问全局对象
  • 版本管理:Schema 带版本号,支持迁移脚本,保证向后兼容
  • 插件化架构:编辑器核心保持精简,所有扩展功能通过插件注册
  • iframe 画布隔离:画布在 iframe 中渲染,与编辑器样式 / 上下文完全隔离
  • 性能预算:设定 Schema 节点数上限(如 500),超过提示拆分页面
  • 可出码:支持将 Schema 导出为源代码,降低平台绑定风险

面试题

1. 低代码平台的 Schema 如何设计?需要包含哪些关键字段?

参考答案:

Schema 是页面结构的 JSON 描述,核心字段包括:

  • schemaVersion:版本号,保证向后兼容
  • id / type:节点唯一标识和组件类型
  • props:组件静态属性
  • bindings:动态表达式绑定(如 {{state.xxx}}
  • events:事件绑定(触发类型 + 动作参数)
  • children:子节点数组,构成组件树
  • state:页面级状态变量
  • dataSources:API 数据源声明
  • logicFlows:逻辑编排定义

设计原则:树形结构递归嵌套、属性与绑定分离、表达式用 {{}} 包裹标识。

2. 渲染器的工作原理是什么?如何从 Schema 渲染出真实页面?

参考答案:

渲染器核心流程:

  1. 读取 Schema 根节点
  2. 根据 type 从组件注册表中查找对应组件
  3. 解析 bindings,将表达式计算为实际值
  4. 解析 events,绑定事件处理函数
  5. 合并 props 和解析后的值,传给组件
  6. 递归处理 children,重复 2-5 步
  7. 最终输出完整的 React/Vue 组件树

性能关键:避免全量重渲染,通过 Schema diff 做增量更新;大量节点使用虚拟化渲染。

3. 拖拽功能如何实现?有哪些技术方案?

参考答案:

主流方案:

  • HTML5 Drag and Drop API:浏览器原生,兼容性好但 API 繁琐,移动端不支持
  • dnd-kit(React):声明式 API,支持排序、嵌套、多容器,社区活跃
  • SortableJS:框架无关,功能丰富,jQuery 时代遗留方案
  • 自研拖拽引擎:基于 mousedown/mousemove/mouseup,完全可控

编辑器中的拖拽需处理:

  • 组件面板 → 画布(新增节点)
  • 画布内排序(移动节点)
  • 嵌套容器(父子关系变更)
  • 拖拽预览(DragOverlay)
  • 碰撞检测(closestCenter / closestCorners)

4. 表达式沙箱如何实现?为什么不能直接用 eval?

参考答案:

直接 eval 的问题:

  • 可访问 windowdocument 等全局对象,造成 XSS
  • 可执行任意代码,如 fetch 发起请求、修改 DOM
  • 安全风险不可控

沙箱实现方案:

  • Proxy + with:用 Proxy 拦截属性访问,白名单模式只允许访问 context 变量
  • iframe 沙箱:在独立 iframe 中执行表达式,完全隔离
  • AST 解析:解析表达式 AST,只允许安全操作(如属性访问、算术运算)
  • mathjs:使用 math.js 的 evaluate,只支持数学表达式
  • Comlink / Worker:在 Web Worker 中执行,隔离主线程

5. 大型 Schema(如 500+ 节点)渲染性能如何优化?

参考答案:

  • 虚拟化渲染:只渲染可视区域内的组件节点,类似虚拟列表
  • 增量更新:Schema 变更时 diff 计算最小变更子树,只重渲染受影响部分
  • 组件懒加载:使用 React.lazy 按需加载组件代码
  • 缓存策略React.memo + 浅比较,避免无变化子树重渲染
  • 编辑 / 运行时分离:编辑器中可降级渲染(如用占位符替代真实组件),发布版本全量渲染
  • Web Worker:Schema 解析、表达式计算放到 Worker 线程
  • 节点数限制:设定单页面节点上限,引导用户拆分页面

6. 如何让低代码平台支持自定义组件的扩展?

参考答案:

扩展体系三层设计:

  1. 组件注册:提供 registerComponent(name, component, meta) API,自定义组件按统一规范注册
  2. 元信息声明:组件需提供 meta(属性定义 / 设置器 / 快捷片段 / 图标 / 分组),编辑器据此生成属性面板和组件面板
  3. Setter 扩展:属性设置器可自定义注册(registerSetter),如渐变色选择器、图标选择器

关键设计:

  • 组件与编辑器解耦:组件不依赖编辑器 API,只依赖 props
  • 组件沙箱化:自定义组件在隔离环境中渲染,不影响其他组件
  • 版本兼容:组件声明支持的 Schema 版本范围

7. 什么场景下应该使用低代码?什么场景下不该用?

参考答案:

适合用低代码:

  • 中后台 CRUD 页面,重复度高
  • 内部工具 / 管理后台,需求变化快
  • 表单 / 问卷 / 数据看板,结构化程度高
  • 营销落地页,活动频繁需快速上线
  • 原型验证,快速试错

不适合用低代码:

  • 高交互复杂度应用(游戏、3D 编辑器、在线文档)
  • 极致性能要求页面(首屏 SSR、大量动画)
  • 高度定制化 UI(品牌官网、创意交互)
  • 核心业务逻辑复杂且需长期维护的系统
  • 对可移植性要求高的产品(平台绑定风险)

8. 低代码 vs 纯代码的权衡取舍是什么?

参考答案:

维度Low-code 优势Pro-code 优势
效率标准场景 3-5 倍提效复杂场景无限制
灵活度受组件库和 Schema 表达能力限制无限制
性能Schema 解析 + 动态组件有开销可极致优化
可维护性依赖平台,人员流动不影响代码即文档,但需规范
可移植性低(平台绑定)高(标准技术栈)
团队协作天然支持多人在线编辑需 Git + CR 流程
调试逻辑编排调试困难断点 / 日志 / DevTools

最佳策略:核心业务 Pro-code + 边缘页面 Low-code 的混合模式。部分平台支持”出码”能力,可从 Schema 导出源代码,兼顾效率与可控性。


相关链接