可视化编辑工具开发回顾 part2 - 编辑器

2020-03-14#CODING

其实对于编辑器的构思是比配置更早的事情。因为在还没有开发过『可视化编辑』工具的时候,一想到这类工具就觉得很厉害。因为它可以脱离程序员,交给运营人员来操作,不停的生产页面。

所以编辑器该怎么做呢?再真正开始动手之前,我们毫无概念,好在找到了这些文章:

上篇文章说到一个页面的核心其实是一份配置,回顾一下配置的结构:

1 { 2 "instance_id_1": { 3 "key": "instance_id_1", 4 "componentName": "", 5 "slots": { // 父子关系 6 7 } 8 "data": { 9 "propsData": {}, 10 "style": {} 11 } 12 }, 13 "instance_id_2": {} // 另一个组件的结构 14 } 15

这些配置应该如何修改呢?最简单的就是暴露一个输入框,让别人把 json 配置填进去了,直接放到配置上面的相应位置就可以了。哈哈,这当然是开玩笑,但却涉及到一个问题,我们该暴露什么样的交互让用户修改配置?

编辑插件

比如在 propsData 里面的属性,都是一些静态属性,颜色文案之类的。不同的字段类型对应不同的组件。比如:

  • 文案:输入框
  • 布尔值:switch 开关
  • 数字:滑杆
  • 颜色:拾色器

当用户选中一个组件,编辑器马上可以根据那个组件的 id,拿到相应的配置,映射成相应的可视编辑组件。大概长这个样子:

Xnip2020-03-14_18-22-33.pngXnip2020-03-14_18-22-33.png

图中的组件有这些属性暴露出来供编辑:

  • 最小高度 → 数字 → 滑杆
  • 背景颜色 → 颜色 → 拾色器

当用户进行一个编辑操作,数据流是这样的:

用户发生了交互,这些组件提交修改后的值,编辑器找到当前编辑的组件节点,把值修改到 propsData 下相应的字段。整个流程如下图:

excalidraw-2020314183129-2.pngexcalidraw-2020314183129-2.png

但只有这些交互还不够,为了更适用于内部业务,还需要更多的编辑组件。比如上传图片。或者其他和业务强耦合的组件,比如搜索某个用户,获取其头像展示在页面上等。

从上图中可知道,不管用户发生了什么交互,编辑组件提交了什么值,到编辑器这里,都只是一个值,然后放到配置里面。也就是前面的交互是编辑组件范畴内的工作,编辑器只关心结果,也就是编辑组件提交给编辑器的那个值

它们的关系如此松散,这些编辑组件完全可以独立于编辑器之外,或者把它们叫成编辑插件更合适!

当然,除了接受编辑插件提交的修改值外,编辑器还要去渲染这些编辑插件。渲染的前提是,编辑器要认识这个编辑插件,之后才能根据不同的配置类型,渲染不同的插件。

在我们基于 vue.js 的实现里,给了每个插件一个 name 属性,大概长这个样子:`plugin-type-string`。编辑器可以根据最后的 string,知道这个插件是主管什么类型的字段的。

所以编辑器和编辑插件的关系是这样的:

excalidraw-2020314183129.pngexcalidraw-2020314183129.png

渲染器

既然是可视化工具,编辑了配置之后,肯定要实时渲染。有了配置,其实这一步就容易了。但在这里需要考虑一个问题:渲染器是用 iframe?还是挂载在相同 dom 树?

一开始,我们把渲染器挂载 dom 树下面,这样有一个好处,是因为在同一个 dom 树下,做各种修改都很方便。

但后面遇到了 CSS 样式冲突之类的问题,或者组件里面有人搞了大新闻,一下子把整个 dom 树干掉之类的。

转到 iframe 之后这些问题都不存在了,因为是独立的环境了。但隔了一层又导致了其他问题,比如拖拽的处理之类的。好在这些问题都不难解决。

放到 iframe 里面还有一个额外的好处,就是渲染器的运行时框架和编辑器可以完全分离!

渲染器需要接受的只是编辑器传过来的页面的完整配置,而怎么渲染是渲染器的事情。只要能解析配置并渲染即可。

组件

编辑器里可以被用户编辑的单元叫做组件。组件的结构是这样的:

excalidraw-2020314183129-2 1.pngexcalidraw-2020314183129-2 1.png

component logic 就是组件本身的逻辑,编辑器不 care 这一部分,只要别把搞大新闻就行。编辑插件那部分说的,组件的 propData 里面的字段会根据类型对应不同的编辑插件。但是编辑器又不智能,它没办法知道这个 prop 该对应什么编辑插件。

谁知道?当然是开发组件的人!组件的构成里,除了自身的逻辑,还有一份配置表。这个配置表就是把组件对外暴露的属性和编辑插件对应起来。

那结构图里面的自定义编辑插件是什么?如果组件的开发者找不到可以满足其需求的编辑插件怎么办?或者编辑插件的交互很复杂,涉及到业务的各种接口怎么办?

编辑器在读取一个组件的配置表时,如果发现某个属性对应的编辑器是 `custom` 的,并且附带了 editorComponent 字段,就会把这个 editorComponent 渲染出来。如前面所说的,编辑器并不管编辑插件里面如何运作,到最后把编辑的值提交上来就行。

编辑器

说了这么久,编辑器的职责到底是什么?目前所知:

  1. 对于编辑插件而言,它大概暴露了一些接口出来,供提交修改值。
  2. 对于组件而言,在组件被编辑的时候,它帮渲染编辑插件,并把修改维护到页面配置的相应节点上。
  3. 对于页面配置而言,编辑器就是它的容器或者加工厂,读取配置,然后修改配置,最后导出配置。
  4. 那对于用户而言呢?他们看到的编辑器是什么样子的?

如下图:

excalidraw-2020314183129 1.pngexcalidraw-2020314183129 1.png

左边,是所有被加载进来的组件。

**中间,**是渲染器,用户可以从左边的组件列表,通过拖拽放到渲染器那里。渲染器同时也承担了画布的角色。

**右边,**是编辑插件。组件被选中后,其暴露出来的属性对应的编辑插件也显示了出来。用户在这里进行组件的某个属性的配置。

所以编辑器承担了:

  1. 组件的加载,及其编辑插件的渲染。
  2. 相应的组件属性的修改,和维护页面配置。
  3. 相应页面配置的变化,交给渲染器去实时渲染。

可以说,编辑器是一个整合者,围绕在它身边的是组件、编辑插件;它的内部是面向用户的拖拽交互、配置的维护。

最后

如前面所说,围绕在编辑器周边的组件和编辑插件。所以可视化工具并不是一个编辑器而言,还有这些围绕周边的组件和插件如何接入的问题。

因为笔者所在的业务属于基础业务,所以编辑器就是基础业务在维护。但更重要的是,要让其他的各业务部门有接入的动力。其他业务在这里就是围绕着编辑器的组件。

这关系就好像国际空间站和飞船一样。国际空间站需要有降落的位置,飞船才能来来往往。这也是下一篇要说的内容,会涉及到组件的开发环境、组件的维护和版本发布等。

🩷
0
👍
0
😄
0
🙁
0