低代码与搭建平台
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-code | Pro-code | No-code | CMS |
|---|---|---|---|---|
| 开发效率 | 高(拖拽 + 少量代码) | 低(全量手写) | 极高(纯配置) | 中(内容配置) |
| 灵活度 | 中高 | 极高 | 低 | 低 |
| 学习门槛 | 中 | 高 | 低 | 低 |
| 可维护性 | 依赖平台 | 完全可控 | 依赖平台 | 依赖平台 |
| 性能上限 | 受 Schema 渲染开销限制 | 可极致优化 | 受平台限制 | 一般 |
| 适用场景 | 中后台、营销页 | 所有场景 | 简单表单 / 问卷 | 内容展示 |
| 团队协作 | 天然支持 | 需额外方案 | 天然支持 | 天然支持 |
| 可移植性 | 低(平台绑定) | 高 | 极低(平台绑定) | 低 |
知名平台
| 平台 | 类型 | 特点 |
|---|---|---|
| 钉钉宜搭 | Low-code | 阿里出品,钉钉生态深度集成 |
| 腾讯微搭 | Low-code | 腾讯云生态,小程序支持 |
| 阿里低代码引擎(lowcode-engine) | 引擎 | 开源,可二次开发,生态丰富 |
| Amis(百度) | JSON-Driven | JSON Schema 驱动 UI,前端零代码 |
| Retool | Low-code | 内部工具搭建,数据库直连 |
| Appsmith | Low-code | 开源,JS 扩展,数据源丰富 |
| Bubble | No-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 树 |
| Node | Schema 树节点,对应一个组件实例 |
| 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 导出 / 导入权限 |
常见陷阱
| # | 陷阱 | 说明 | 解决方案 |
|---|---|---|---|
| 1 | Schema 无限嵌套导致渲染栈溢出 | 组件树层级过深或循环引用 | 渲染时设置最大深度限制(如 50 层),Schema 校验时检测循环引用 |
| 2 | 表达式 eval 直接执行用户输入 | 存在 XSS / 代码注入风险 | 使用沙箱执行,白名单变量访问 |
| 3 | 画布拖拽性能卡顿 | 节点数过多时每次拖拽全量重渲染 | 虚拟化渲染,只渲染可视区域节点;增量更新 |
| 4 | 组件注册名冲突 | 不同组件库注册相同 componentName | 使用命名空间前缀,如 Basic.Button / Chart.Button |
| 5 | Schema 版本不兼容 | 升级 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 渲染出真实页面?
参考答案:
渲染器核心流程:
- 读取 Schema 根节点
- 根据
type从组件注册表中查找对应组件 - 解析
bindings,将表达式计算为实际值 - 解析
events,绑定事件处理函数 - 合并
props和解析后的值,传给组件 - 递归处理
children,重复 2-5 步 - 最终输出完整的 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 的问题:
- 可访问
window、document等全局对象,造成 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. 如何让低代码平台支持自定义组件的扩展?
参考答案:
扩展体系三层设计:
- 组件注册:提供
registerComponent(name, component, meta)API,自定义组件按统一规范注册 - 元信息声明:组件需提供
meta(属性定义 / 设置器 / 快捷片段 / 图标 / 分组),编辑器据此生成属性面板和组件面板 - 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 导出源代码,兼顾效率与可控性。
相关链接
- 阿里低代码引擎(lowcode-engine) — 阿里开源低代码引擎官方文档
- lowcode-engine GitHub — 源码仓库
- Amis 官方文档 — 百度 Amis JSON 驱动 UI 框架
- Amis GitHub — 源码仓库
- dnd-kit — React 拖拽库
- formily — 阿里开源 Schema 驱动表单方案
- Appsmith — 开源低代码平台
- Retool — 内部工具低代码平台
- Bubble — 零代码全栈搭建平台
- 腾讯微搭 — 腾讯云低代码平台
- 钉钉宜搭 — 阿里钉钉低代码平台