# 初探富文本之编辑器引擎
在前文中我们介绍了富文本的基础概念,以及富文本的基本发展历程,那么在本文中将会介绍当前主流开源的富文本编辑器引擎。当前使用最广泛的富文本编辑器是`L1`的富文本编辑器,其能满足绝大部份使用场景,由此也诞生了非常多优秀的开源富文本引擎,这其中有仅提供引擎的编辑器例如`Slate.js`,也有提供了部分开箱即用的功能的例如`Quill.js`,也有基于这些引擎二次开发的例如`Plate.js`,本文主要介绍了`Slate.js`、`Quill.js`、`Draft.js`三款编辑器引擎。
初探富文本编辑器系列相关文章
* [初探富文本编辑器#1-富文本概述](./初探富文本之富文本概述.md)
* [初探富文本编辑器#2-编辑器引擎](./初探富文本之编辑器引擎.md)
* [初探富文本编辑器#3-OT 协同算法](./初探富文本之OT协同算法.md)
* [初探富文本编辑器#4-OT 协同实例](./初探富文本之OT协同实例.md)
* [初探富文本编辑器#5-CRDT 协同算法](./初探富文本之CRDT协同算法.md)
* [初探富文本编辑器#6-CRDT 协同实例](./初探富文本之CRDT协同实例.md)
* [初探富文本编辑器#7-React 实时预览](./初探富文本之React实时预览.md)
* [初探富文本编辑器#8-文档 diff 算法](./初探富文本之文档diff算法.md)
* [初探富文本编辑器#9-在线文档交付](./初探富文本之在线文档交付.md)
* [初探富文本编辑器#10-划词评论能力](./初探富文本之划词评论能力.md)
* [初探富文本编辑器#11-文档虚拟滚动](./初探富文本之文档虚拟滚动.md)
* [初探富文本编辑器#12-搜索替换算法](./初探富文本之搜索替换算法.md)
* [初探富文本编辑器#13-序列化与反序列化](./初探富文本之序列化与反序列化.md)
## Slate.js
`slate`是一个仅仅提供引擎的富文本`core`,简单来说他本身并不提供各种富文本编辑功能,所有的富文本功能都需要自己来通过其提供的`API`来实现,甚至他的插件机制也需要通过自己来拓展,所以使用`slate`来构建富文本编辑器的话可定制度相当高。`slate`的文档虽然不是特别详细,但是他的示例是非常丰富的,在文档中也提供了一个演练作为上手的基础,对于新手还是比较友好的。话说回来如果只提供一个引擎的话,谁也不知道应该怎么用。
在`slate`的文档中有对于框架的设计原则上的描述:
* 插件是一等公民,`slate`最重要的部分就是插件是一等公民实体,这意味着你可以完全定制编辑体验,去建立像`Medium`或是`Dropbox`这样复杂的编辑器,而不必对库的预设作斗争。
* 精简的`schema`核心,`slate`的核心逻辑对你编辑的数据结构进行的预设非常少,这意味着当你构建复杂用例时,不会被任何的预制内容所阻碍。
* 嵌套文档模型,`slate`文档所使用的模型是一个嵌套的,递归的树,就像`DOM`一样,这意味着对于高级用例来说,构建像表格或是嵌套引用这样复杂的组件是可能的,当然你也可以使用单一层次的结构来保持简单性。
* 与`DOM`相同,`slate`的数据模型基于`DOM`,文档是一个嵌套的树,其使用文本选区`selections`和范围`ranges`,并且公开所有的标准事件处理函数,这意味着像是表格或者是嵌套引用这样的高级特性是可能的,几乎所有你在`DOM`中可以做到的事情,都可以在`slate`中做到。
* 直观的指令,`slate`文档执行命令`commands`来进行编辑,它被设计为高级并且非常直观地进行编辑和阅读,以便定制功能尽可能地具有表现力,这大大的提高了你理解代码的能力。
* 可协作的数据模型,`slate`使用的数据模型特别是操作如何应用到文档上,被设计为允许协同编辑在最顶层,所以如果你决定要实现协同编辑,不必去考虑彻底重构。
* 明确的核心划分,使用插件优先的结构和精简核心,使得核心和定制的边界非常清晰,这意味着核心的编辑体验不会被各种边缘情况所困扰。
### 示例
这样*一段文本*的**数据结构**如下所示。
```js
[
{
children: [
{ text: "这样" },
{ text: "一段文本", italic: true },
{ text: "的" },
{ text: "数据结构", bold: true },
{ text: "如下所示。" },
],
},
];
```
### 优势
* 可定制化程度非常高,几乎所有富文本表现层的功能都需要自行实现。
* 非常轻量,本体只有一个内核,需要什么就做什么功能,体积可控。
* 在设计架构时就针对协同提供了`OP`化的差量变更操作。
* 数据结构是类似于`DOM`的嵌套`JSON`结构,比较直观容易理解。
### 不足
* 依旧处于`Beta`阶段,可能会有重大`API`变化,例如`0.50`版本就是全新重构的。
* 虽然有协同的设计,但没有转换操作的`OT`算法或`CRDT`算法的直接支持。
* 仅有内核的架构同样也是不足,所有的功能都需要自行实现,成本比较高。
* 新版`slate`是无`schema`的,这也就意味着`Normalize`需要自行实现。
### 参考
* `slate`官方文档`https://docs.slatejs.org/`。
* `slate`官方示例`https://www.slatejs.org/examples/richtext`。
* 个人基于`slate`实现的富文本编辑器`https://github.com/WindrunnerMax/DocEditor`。
* 基于`slate`的开箱即用富文本编辑器`https://plate.udecode.io/docs/playground`。
* `slate`的`OT`协同实现参考`https://github.com/solidoc/slate-ot`。
* `slate`协同的`OTTypes`参考`https://github.com/pubuzhixing8/ottype-slate`。
* `slate`的`CRDT`协同实现参考`https://github.com/humandx/slate-automerge`。
* `slate`与`YJS`协同结合的参考`https://github.com/BitPhinix/slate-yjs`。
* 关于`slate`非常不错的文章`https://github.com/yoyoyohamapi/book-slate-editor-design`。
## Quill.js
`quill`是一个现代富文本编辑器,具备良好的兼容性及强大的可扩展性,还提供了部分开箱即用的功能。`quill`是在`2012`年开源的,`quill`的出现给富文本编辑器带了很多新的东西,也是目前开源编辑器里面受众非常大的一款编辑器。至今为止的生态已经非常的丰富,可以在`GitHub`等找到大量的示例,包括比较完善的协同实例。
在`quill`的文档中有对于框架的设计原则上的描述:
* `API`驱动设计,`quill`所有的功能都是通过`API`来实现的并且可以直观的通过`API`来获得数据的变化,以文本为中心的基础上构建的`API`,不需要解析`HTML`或者`DIFF DOM`树,这样的设计可以让`quill`的功能更加的灵活与更高的可拓展性。
* 自定义内容和格式,`quill`公开了自己的文档模型,这是对`DOM`的强大抽象,允许扩展和定制,由此数据结构的主角变成了`Blots`、`Parchment`、`Delta`。
* 跨平台,`quill`有着比较良好的兼容性,在旧版本的浏览器中也可以相同的方式运行,在用户体验上不同浏览器中也可以有着相同的视图与交互效果,并且可以在桌面和移动设备上使用。
* 易于使用,`quill`携带了部分开箱即用的功能,如果不需要定制的话,这些功能已经足够了,同时`quill`又有着非常高的可拓展性,用来自定义各种功能。
### 示例
这样*一段文本*的**数据结构**如下所示。
```javascript
{
ops: [
{ insert: "这样" },
{ insert: "一段文本", attributes: { italic: true } },
{ insert: "的" },
{ insert: "数据结构", attributes: { bold: true } },
{ insert: "如下所示。\n" },
],
};
```
### 优势
* `API`驱动设计,基础功能的支持很丰富,并且支持拓展。
* 实现了视图层,实现上与框架无关,无论是`Vue`还是`React`都可以轻松使用。
* 使用了更加直观的`Delta`来描述数据结构,本身实现了操作转换的逻辑,可以非常方便地实现协同。
* 生态非常丰富,有着非常多的插件与设计方案可以参考,特别是对于协同的支持可参考的地方非常多。
### 不足
* `Delta`数据结构是扁平的,也就是一维的数据结构,这样在实现例如表格的功能时就比较麻烦。
* `quill 2.0`已经开发了很久了,但是还没有正式发布,目前的`1.3.7`版本已经有很多年没有更新了。
* `quill`自带的功能很丰富,但这也就意味着其包的大小会比较大一些。
### 参考
* `quill`官方文档`https://quilljs.com/docs/quickstart/`。
* `quill`官方示例`https://quilljs.com/standalone/full/`。
* `quill`的`Delta`设计与实现`https://quilljs.com/docs/delta/`。
* `quill`协同的`OTTypes`参考`https://github.com/ottypes/rich-text`。
* `quill`的`OT`协同实现参考`https://github.com/share/sharedb/tree/master/examples/rich-text`。
* `quill`的`CRDT-yjs`的协同实现参考`https://github.com/yjs/y-quill`。
## Draft.js
`draft`是用于在`React`中构建富文本编辑器的框架,其为创建和自定义文本编辑器提供了强大的`API`,并且旨在易于扩展和与其他库集成,与`React`结合可以使开发者在进行编辑器开发时既不用操作`DOM`、也不用单独学习一套构建`UI`的范式,而是可以直接编写`React`组件实现编辑器的`UI`。`draft`整体理念与`React`非常的吻合,例如使用状态管理保存数据结构、使用`immutable.js`库、数据结构的修改基本全部代理了浏览器的默认行为、通过状态管理的方式修改富文本数据等。
在`draft`的`README`中有对于框架的设计原则上的描述:
* 可扩展和可定制,提供了构建块来创建各种丰富的文本组合体验,从基本文本样式到嵌入式媒体的支持。
* 声明式富文本,`draft`无缝融入`React`,使用`React`用户熟悉的声明式的`API`抽象出渲染、选择和输入行为的细节。
* 不可变的编辑器状态,`draft`模型是使用`immutable.js`构建的,提供具有功能状态更新的`API`,并积极利用数据持久性来实现可扩展的内存使用。
### 示例
这样*一段文本*的**数据结构**如下所示。
```javascript
{
blocks: [
{
key: "3eesq",
text: "这样一段文本的数据结构如下所示。",
type: "unstyled",
depth: 0,
inlineStyleRanges: [
{ offset: 2, length: 4, style: "ITALIC" },
{ offset: 7, length: 4, style: "BOLD" },
],
entityRanges: [],
data: {},
},
],
entityMap: {},
};
```
### 优势
* 具有灵活的`API`,可以轻松地扩展和自定义块和内联元素等。
* 使用`React`作为`UI`层以及数据管理,可以充分利用`React`生态,对`React`用户友好。
* 没有过重大的`Breaking Change`,在稳定性与细节的处理上比较具有优势。
### 不足
* 完全依赖于`React`作为`UI`层,与`React`深度绑定,在其他`UI`框架上很难使用。
* 数据结构模型的设计上不是很灵活,在实现表格等嵌套结构时比较受限。
* `draft`针对性能进行了大量优化,但是在呈现大量内容时还是会感受到卡顿。
### 参考
* `draft`官方文档`https://draftjs.org/docs/overview`。
* `draft`官方示例`https://draftjs.org/`。
* `draft`的`codesandbox`示例`https://codesandbox.io/s/github/gupta-piyush19/Draft-JS-Editor`。
## 每日一题
-
## 参考
-
-
-
-
-
-
-
-
-
-
-