
一、实现原理
1. 初始化渲染逻辑
实例化工作区
相关代码
// 1. 实例化工作区
const workspace = new Workspace({
entry: '/src/index.js',
files: sampleFiles,
});
window.__workspace__ = workspace;
Workspace(工作区状态)功能
- 管理当前工作区的文件列表,并且进行转义
- 管理页面路由、store、service 配置文件
- 管理当前的路由、当前选中的视图文件与选中的文件
- 创建通信机制
- 管理 Workspace 历史记录
初始化引擎
引擎包括两部分
- Workspace - 工作区状态
- Designer - 设置器状态
// 2. 引擎初始化
const engine = createEngine({
workspace,
});
window.__workspace__ = workspace;
初始化变量配置
自定义配置数据
{
customActionVariables: bootHelperVariables,
customExpressionVariables: bootHelperVariables,
}
export const bootHelperVariables = [
{
key: '$helpers',
title: '工具函数',
children: [
{
title: 'setStoreValue',
key: '() => tango.setStoreValue("variableName", "variableValue")',
type: 'function',
},
{
title: 'getStoreValue',
key: '() => tango.getStoreValue("variableName")',
type: 'function',
},
{ title: 'openModal', key: '() => tango.openModal("")', type: 'function' },
{ title: 'closeModal', key: '() => tango.closeModal("")', type: 'function' },
{ title: 'navigateTo', key: '() => tango.navigateTo("/")', type: 'function' },
{ title: 'showToast', key: '() => tango.showToast("hello")', type: 'function' },
{ title: 'formatDate', key: '() => tango.formatDate("2022-12-12")', type: 'function' },
{ title: 'formatNumber', key: '() => tango.formatDate(9999)', type: 'function' },
{
title: 'copyToClipboard',
key: '() => tango.copyToClipboard("hello")',
type: 'function',
},
],
},
];
初始化沙箱 Query 工具
一个 DOM Query 工具,通过引用的方式来与 Iframe 沙箱进行通信
const sandboxQuery = new DndQuery({
context: 'iframe',
});
渲染布局
布局很好理解,包括以下部分
- DesignerPanel:壳子
- Sidebar:左侧工具栏面板
- WorkspacePanel
- WorkspaceView design 模式
- WorkspaceView code 模式
- SettingPanel:右侧设置器
初始化沙箱
-
这里的沙箱指的是 WorkspaceView design 模式用到的 CodeSandbox 核心功能,是整个低码编辑器的核心,这里需要引入 CodeSandbox 的 bundler。
JavaScript<Sandbox bundlerURL="https://local.netease.com:8443" onMessage={(e) => { if (e.type === "done") { const sandboxWindow: any = sandboxQuery.window; if (sandboxWindow.TangoAntd) { if (sandboxWindow.TangoAntd.menuData) { setMenuData(sandboxWindow.TangoAntd.menuData); } if (sandboxWindow.TangoAntd.prototypes) { workspace.setComponentPrototypes(sandboxWindow.TangoAntd.prototypes); } } setMenuLoading(false); } }} />; -
在沙箱加载完成之后,会设置
MenuData和ComponentPrototypes -
根据用户操作渲染左侧组件面板和组件的设置面板
2. 沙箱原理
Sandbox 包括 PreviewSandbox 和 DesignSandbox 两种,其中
PreviewSandbox直接渲染了CodeSandbox的预览模式DesignSandbox渲染了CodeSandbox的 Design 模式,添加 useDnD 逻辑,并且监听代码或边框更新的情况重新设置选中的边框
CodeSandbox 对接原理
- 通过 iframe 加载并渲染
codesandbox-client资源 - 在加载完成后注册监听逻辑,并修改 domain,以便让外部页面和 iframe 页面在同一个域名下,主要目的是为了直接监听 iframe 页面的事件
- 加载完成后实例化
Manager,即开始构建页面,其中Manager是一个管理者的角色,从大局上把控整个转译和执行的流程(通过 IFrameProtocol 来进行通信) - 将 iframe ref 传给
Manager作为实例化参数,当构建完成后,会将构建的页面 dom 设置给 iframe ref
3. 插入、复制、删除、移动原理
useDnd 的原理
useDnd 是在渲染沙箱的时候会使用到,宿主会有三个渲染元素,分包用于选中高亮(SelectionTools)、插入提示(InsertionPrompt)、拖拽占位图层(DraggingMask)
<div className="AuxTools">
<SelectionTools actions={selectionTools} />
<InsertionPrompt />
<DraggingMask />
</div>
而 useDnd 本身会有以下功能:
- 处理当前选中的元素、拖拽相关的元素,显示提示
- 处理当前元素的拖拽逻辑,给出拖拽高亮提示
- 操作完成后,执行 Workspace 的 dropNode 能力,对文件进行操作
withDnd 的原理
withDnd 是一个 HOC,每个物料都需要使用该 HOC 定义当前组件的布局属性,并渲染 tango-dndBox 壳子来配合实现 Dnd 逻辑,如:
- 是否允许拖拽
- 布局的基本样式
block、inline-block、inline - 注入
DND 追踪标记(data-dnd)
其中 DND 追踪标记是 Workspace 创建 TangoViewModule 的时候调用 traverseViewFile 注入的
二、框架、物料设计

1. 物料设计
目录结构
+ src
+ button
- view.tsx // 默认视图文件
- index.ts // 渲染视图入口文件
- designer.ts // 设计器视图入口文件
- prototype.ts // 组件描述文件
+ date-picker
- index.ts // 组件包默认入口文件
- designer.ts // 组件包设计器视图入口文件
物料核心包(TangoAntd)是应用必带的基础包,NPM 地址见 @music163/antd,主要有以下功能:
-
暴露物料的 MenuData
JavaScriptexport const menuData = { common: [ { title: '基本', items: ['Button', 'Section', 'Box', 'Space', 'Typography', 'Title', 'Paragraph'], }, { title: '输入', items: ['Input', 'InputNumber', 'Select'], }, { title: 'Formily表单', items: ['FormilyForm', 'FormilyFormItem', 'FormilySubmit', 'FormilyReset'], } ], }; -
暴露物料的组件,包括 withDnD 的逻辑
默认情况下 withDnd 会在组件外层包裹一层 dnd 容器,以便于组件能够在设计器中被拖拽:
- draggable 属性表示该区域可以被拖拽
- data-dnd 用来追踪渲染的 dom 元素
JavaScriptexport const Section = withDnd({ name: 'Section', hasWrapper: false, })(({ isRender = true, children = <Placeholder />, ...rest }: SectionProps) => React.createElement( BaseSection, { opacity: isRender ? undefined : 0.4, ...rest, }, children, ), ); -
暴露物料组件的基本描述和设置器设置
JavaScriptexport const Section: ComponentPrototypeType = { name: 'Section', title: '布局区块', icon: 'icon-mianban', type: 'element', package: '@music163/antd', help: '区域容器,可以用来将页面划分成多个区域,每个区域放置具体的内容模块。', hasChildren: true, initChildren: '', props: [ // ...IsRenderPrototypes, ...CommonSystemStylePrototypes, ...StylePrototypes, { name: 'title', title: '容器标题', setter: 'textSetter', initValue: '区块标题', }, { name: 'shape', title: '容器外观', setter: 'choiceSetter', options: [ { label: '卡片', value: 'panel' }, { label: '正常', value: 'box' }, ], }, { name: 'span', title: '占据的列数', tip: '仅在容器为弹性容器时才生效', setter: 'numberSetter', setterProps: { max: 24, min: 1, }, }, { name: 'extra', title: '页头附加内容', setter: 'jsxSetter', }, ], rules: { childrenContainerSelector: '.one-section-content', }, };
2. 应用框架设计
应用框架核心包(TangoBoot) 指的是在该编辑开发的应用所要遵循的开发规范以及框架,方便后续解析和操作
目录结构
── src
│ +── assets
│ +── pages
│ +── components
│ +── services/index.js
│ +── stores
│ ├── routes.js // 路由配置
│ ├── global.less // 全局样式
| |-- index.js 应用启动配置
└── package.json
|---tango.config.json 设计器和 external 配置
在 Workspace 中定义的文件类型
/**
* 文件类型枚举
*/
export enum FileType {
// js 文件
Module = 'module',
StoreEntryModule = 'storeEntryModule',
RouteModule = 'routeModule',
BlockEntryModule = 'blockEntryModule',
ServiceModule = 'serviceModule',
StoreModule = 'storeModule',
JsxViewModule = 'jsxViewModule',
JsonViewModule = 'jsonViewModule',
// 非 js 文件
PackageJson = 'packageJson',
TangoConfigJson = 'tangoConfigJson',
AppJson = 'appJson',
File = 'file',
Json = 'json',
Less = 'less',
Scss = 'scss',
}
路由、状态管理(略)
这里有个遗留问题,assets 中允许存非文本文件吗?至少 CodeSandbox 是支持的
Reference
GitHub - NetEase/tango: A source code based low-code builder. Integrate low-code experience into your local development workflow seamlessly.
A source code based low-code builder.
https://github.com/NetEase/tango
GitHub - NetEase/tango-components: An UI library for tango low-code builder
An UI library for tango low-code builder.
https://github.com/NetEase/tango-components
Discussion
留言与讨论
想法、补充和不同意见都欢迎。