在经历了一年时间,两个大的架构设计变动下,至今,TBus 富文本编辑器的基础设计基本稳定。我决定将 TBus 富文本编辑器开源,在各路大神的锐利的目光下,能走得更远。
TBus 的前世今生 前端发展到现在,富文本编辑器也可以说多如牛毛,为什么我还要自己写一个富文本编辑器呢?
个人太菜!!!
这句话倒不是自谦,由于我们公司使用的是我写的 UI 组件库,最初是把 quill 封装成了一个组件,但 quill 对表格支持不好,当时在网上也没找到合适的插件。后来,想到了 UEditor,但 UEditor 很久没更新了,对前端工具链不友好。也试用了 wangEditor,但 Angular cli 打包时会报错……。
在试过一系列富文本之后,我造轮子的心又开始躁动了。
第一版
于是,在几个月的时间里,我写出了 TBus 的第一个版本。和大多数富文本编辑器一样,基于 contentEditable,在基本有一个雏形之后,心里却越来越没底。主要是发现在以下问题:
- 内容不可控,由于 HTML 的灵活性,让富文本复杂度成倍的提升。所以,当用户在使用后,到底会产生什么样的内容,我是不知道的。
- 内容太脏,一段文字的加粗,可以是一个 strong,也可以每个字一个 strong,还可以是其它标签加 css 等。
- 扩展困难,基本上新加一个功能,要面对的问题就是整个富文本的问题,很难做到很好的屏蔽底层的坑。
因为上述问题,我又到网上,包括知乎来搜索富文本相关的文章,只要关于富文本,一股脑全看,这时看到了 Draft.js、Slate.js 这样的,数据和视图分开的富文本框架。觉得这是一个很好的解题思路。但同时也看到了这样的结构的一些局限性。在当时的了解下,很多文章表示,Draft.js 对表格支持不友好,绑定 React 等,还有性能问题。
性能问题,也许可以靠优化来解决,但如果架构设计上,对复杂结构支持不友好,或对技术选型绑定的话,基本上就表示,这个东西的应用场景是有限制的。
虽然我并不是很认可 Draft.js 的结果,但是其设计思路还是给了我很大的启发。
第二版
于是,我又着手了 TBus 第二版的研发。这一版抛弃了 contentEditable,并且采用了从数据到视图的架构。并且因为从一开始,我就考虑到了如表格这样的复杂数据结构,所以结果也基本符合预期。
第二版解决了如下问题:
- 内容可控,因为操作的是数据,用户所有操作其实都是被劫持的。
- 内容了不脏了,这算是 TBus 至今的亮点,在 TBus 中,如加粗一段文字,一定只有一个 strong 标签,不会出现多个 strong 并列的情况。
- 扩展相对容易,只要把数据处理好,TBus 会自动渲染并生成最简洁的内容。
到这里,一般的富文本编辑器,也就差不多了,但我还是发现了一些问题:
- 怎么保证 ul 下面一定是 li?
- 怎么保证 table 下面是 tbody,tbody 下面是 tr?
如上,还可以类推,如果我要固定一段结构,无论用户怎么操作,都不会影响到这一段结构的稳定性?
其实,上面的话还可以这样说,如何保证,只有一部分内容是可编辑的,另一部分不可编辑?
这需要设计,要从设计上保证,最好这部分数据对编辑操作不可见。
第三版
第三版,即现在的版本。TBus 把富文本抽象成了两部分内容,分别是 Fragment 和 Template。
Fragment 用来保存可编辑片段数据。
Template 用来保存不可编辑或固定结构的数据。
基于以上设计,在 TBus 的扩展功能变得非常容易,甚至可以轻松的定制自己的模板,让 TBus 支持各式各样的格式,而不是仅仅限制在浏览器常见的排版风格上。如果硬要总结 TBus 的亮点,我觉得有以下几点吧。
- 输出干净,没有冗余的标签和样式
- 支持代码实时高亮
- 支持表格框选操作,批量格式化,拆分,合并等
- 支持图片、视频拖动放大缩小
- 支持自定义模板,可以扩展出任意的格式
- Typescript 开发,所有功能都是插件化的,易于定制和扩展
下面贴上 TBus 的演示地址,如果大家觉得还很,还希望顺手在 github 点个 star,以示鼓励!
顺带说一下后续工作:
- 修复各种 bug
- 优化 diff 算法,使之更高效
- 优化模板扩展方式,使之能尽量自动化
- 开发更多的优质模板,供伸手常使用
- 完善文档,方便大家理解
- 完善单元测试,使 TBus 能更茁壮的成长