持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情
名词解释:
编辑器: 低代码中的编辑器可以理解为左侧的物料区域(组件库)以及右侧的属性编辑区域。
渲染器: 低代码中的渲染器可以理解为中心区域的画布区,用来呈现你编辑后的页面效果。
如图所示:
红色为编辑器,蓝色为渲染器
原先的做法思路:
可以看到,我们红框区域是一层遮罩层,而绿色区域就是渲染层。
而在遮罩层,咱们做的事情就可以有很多了,比如拦截拖拽操作,从左侧物料区域拖拽至中心区域后,告知渲染层去渲染组件,与选中组件操作,当我们在遮罩层选中组件后,告知渲染层当前选中了哪个组件,等等操作。
原先做法的实现:
(1)获取渲染器中所有的物料组件
(2)在遮罩层上,动态生成组件对应的的div元素,可以理解为其实每一个组件在遮罩层中,就是一个div。(给你一个假象,你在拖拽移动的时候,是在操作这个组件,其实是在操作这个div)
(3)选中时,动态添加选中框样式。如图所示:
(4)设置遮罩层zIndex大于渲染层的zIndex。
原先做法的总结:
可以看到,我们确实是完全实现了画布的组件编排能力,但是,渲染器和编辑器完全耦合在一起,如今我的平台是vue3技术栈,这也意味着我的渲染器也就是vue3技术栈,那如果今天,我们需要去兼容vue2,react的平台能力,就会愈加麻烦。
那我们该如何去解决这个问题?这里我们就要引入一个运行时的概念,顾名思义,这个运行时就是渲染组件组成的运行环境,它应该独立于我们的编辑器区域,而不是依赖。
调研:
参考了业界有名的低代码平台,如阿里的低代码引擎,腾讯的tmagicEditor,他们都完完全全实现了编辑器与渲染器的解耦,
阿里的解耦做的更狠一些,直接把遮罩层的能力也解耦开来了,而腾讯保留了遮罩层能力。
可以明显看到,都使用到了iframe做运行时,这里我们也使用iframe做一个运行时,即渲染器,接下来,我们就来探讨下如何进行实现。
思路:
首先,我们如何去实现编辑器与渲染器的通信能力,同学们很快就想到了,使用iframe的postMessage事件,但我深入了腾讯的低代码引擎源码,发现了一个黑科技操作,在iframe的window中定义一个属性,在它加载后,赋予contentWindow上的该属性一个值,当iframe执行script的时候,就可以拿到这个值。
简单实现:
el.appendChild<HTMLIFrameElement>(iframe);
iframe.contentWindow.属性 = 值
不过这两行代码我卡住了很久,我思考为什么iframe在执行的时候能拿到这个动态赋予的值呢?,我把两行代码顺序换一下,就会报错contentWindow没这个属性。而appendChild又是一个异步事件,iframe中的script脚本执行时机,我们并不知道。如果评论区有小伙伴知道的话,可以评论一下!
具体实现:
编辑器
el.appendChild<HTMLIFrameElement>(iframe);
iframe.contentWindow.runtimeApi = {
emitRuntimeReady: (runtime: any) => {
window.runtime = runtime;
},
}
渲染器
window.runtimeApi.emitRuntimeReady({
add(v: any) {
},
update(config:any) {
},
remove(id: string) {
},
clearAll() {
},
});
这样,在编辑器加载iframe后,便能拿到渲染器的运行时,当编辑器在进行某些操作时候,就可以去告知渲染器去进行动态渲染。基于此,我们也做到了完全的解耦,可以有3、4套不一样的运行时,因为对于编辑器而言,只是一个iframe的url的差别,然后就可以获取不同运行时的操作api。
感谢观看!