这篇文章不是为了教你如何10分钟内写出一个编辑器,如果你想速成,那就不用往下读了。
1.富文本编辑器是一个天坑
这是前端自古流传下来的一句话,哪怕你从没接触过这东西也应该听过这么句话。我猜这是 uEditor 的一位在凌晨改bug改到崩溃的用户发出的呐喊😄。
我第一次接触的富文本编辑器是大名鼎鼎的 uEditor,第一印象就是丑,外观看起来就很丑的样子,后面慢慢尝试读它的代码,发现它不仅外观丑,代码也是乱七八糟的。
在一个夜深人静的夜晚,仔细想了想这句话,觉得最大的坑其实就是contenteditable带来的浏览器兼容性以及各浏览器厂商对浏览器命令的支持不一,我们往下看……
2.动手写编辑器
其实现在写一款编辑器很简单,市面上九成以上的编辑器都离不开两大法宝
1. contenteditable
2. document.execcommand
我相信掌握了这两项能力,你脑子里已经出现了一款编辑器的雏型。网上那些10分钟速成编辑器的教程,100%离不开这两点,剩下的无外乎就是样式、功能拓展等,最简单的编辑器可能都用不到100行代码。感兴趣的可以看一下 pell,这是目前为止我读过最简单明了的编辑器
一款常规编辑器的核心就是这么点东西,我们通过调用浏览器命令去响应用户操作,当然,最终解释权归人家浏览器啦。
简单归简单,但是这样做出来的编辑器是不受控的,用户的输入,浏览器命令的解释都不是我们的代码能控制的。React等现代框架带给了我们一个美好的未来,让我们能专注于data,一切用户视图都是可控的,那么我们做出来的这款编辑器其实是不符合 数据<-->视图 模型的,数据对我们来说可能只是一串序列化之后的html代码。
我简单把编辑器拆分成两块,core模块与plugins模块。
core 核心模块
- 控制编辑区域
- 控制光标
- 控制selection选区
- 监听编辑器行为(用户操作,包括插件行为)
- 提供插件注册能力
- 向插件传递部分能力
plugins 插件
- 进行能力拓展(字号,颜色,插入元素等)
这么做的目的是为了更好的向插件提供安全的能力。
编辑器本身应该是一个插座,它能做什么取决于插座外接了哪些“电器”。一个好的插座不会因为某个电器有问题导致所有电器都不可用,甚至烧毁自身。
插件系统通常会是整个编辑器最复杂的模块,难的不是如何下发能力,而是如何控制第三方的能力,粗暴点的可以把整个编辑器实例传给插件,这样插件会拥有无穷无尽的能力(例如 wangEditor)。如果某个插件想做点坏事,那也是易如反掌。
一个好的插件系统其实是比较像单向数据流的概念的,上层的应用插件往往需要借助底层core核心区的能力,但是却无法修改这种能力(就像数据不可变),另外核心区需要建立上报和广播机制(生命周期),用来进行事件分发。
目前我自己写的一款编辑器 crayon-editor 就是采用这种模式进行开发的。
3.我理想中的编辑器
上面列举的只是一款开源编辑器的基础架构,基于这套架构做出来的编辑器还是命令驱动式,底层能力并没有发生根本变化。那么除了命令驱动式,还有其他模式么?那就是数据驱动
编辑器架构——数据驱动
接触过react和vue的人对数据驱动应该很熟悉,简单来说就是将数据映射成视图dom,一切的修改都是对数据操作,最终以数据重新渲染为结束。也就是将编辑器的输入输出都抽象成module,用户的操作由原先直接操作dom,转变为对数据的操作,最后产出结果也是module,然后再结合上目前成熟的react、vue作为module渲染,最终形成一个完整的编辑逻辑。在这其中编辑器需要负责翻译、解释dom和module,并将所有动作都映射到对module的修改上,是不是有点像 AST。
所以数据驱动的编辑器是一定会抛弃contenteditable与document.execcommand,因为他们两都属于不可控因素,会导致最终dom和module不一致。
当然这种方案复杂度会非常高,比如首先就要解决如何编辑以及光标的问题,以及后续的浏览器指令需要做怎样的映射。目前我了解到的也就只有 draft.js 和 trix 两者是这种模型,二者都是基于react的。
这是目前最先进的编辑器方案,实现了一款完全可控的编辑器,并且多人协同在线编辑也不在话下。结合上不可变数据immutable,用户的操作轨迹也可以进行记录……
插件——拓展能力
对于富文本编辑器来说,插件就意味着能力,但是无论开发者如何努力也无法满足所有人的需求,面对个性化需求,兼容自定义开发插件的能力也是必须要有的
简介的外观——美
我不用百度的uEditor很大一部分原因就是它比较丑
活跃的用户群体——用户粘性
维护好一个社群是非常关键,社群里大家反馈的问题如果长时间得不到相应,大家往往会觉得这个项目已死。uEditor即便有这么多问题,但它依旧是国内数一数二的编辑器,我觉得最大的原因就是用户基数庞大。
结语
上面就是我对于编辑器的一些想说的话