在前文中我们介绍了富文本的基础概念,以及富文本的基本发展历程,那么在本文中将会介绍当前主流开源的富文本编辑器引擎。当前使用最广泛的富文本编辑器是L1
的富文本编辑器,其能满足绝大部份使用场景,由此也诞生了非常多优秀的开源富文本引擎,这其中有仅提供引擎的编辑器例如Slate.js
,也有提供了部分开箱即用的功能的例如Quill.js
,也有基于这些引擎二次开发的例如Plate.js
,本文主要介绍了Slate.js
、Quill.js
、Draft.js
三款编辑器引擎。
slate
是一个仅仅提供引擎的富文本core
,简单来说他本身并不提供各种富文本编辑功能,所有的富文本功能都需要自己来通过其提供的API
来实现,甚至他的插件机制也需要通过自己来拓展,所以使用slate
来构建富文本编辑器的话可定制度相当高。slate
的文档虽然不是特别详细,但是他的示例是非常丰富的,在文档中也提供了一个演练作为上手的基础,对于新手还是比较友好的。话说回来如果只提供一个引擎的话,谁也不知道应该怎么用哈哈。
在slate
的文档中有对于框架的设计原则上的描述:
slate
最重要的部分就是插件是一等公民实体,这意味着你可以完全定制编辑体验,去建立像Medium
或是Dropbox
这样复杂的编辑器,而不必对库的预设作斗争。schema
核心,slate
的核心逻辑对你编辑的数据结构进行的预设非常少,这意味着当你构建复杂用例时,不会被任何的预制内容所阻碍。slate
文档所使用的模型是一个嵌套的,递归的树,就像DOM
一样,这意味着对于高级用例来说,构建像表格或是嵌套引用这样复杂的组件是可能的,当然你也可以使用单一层次的结构来保持简单性。DOM
相同,slate
的数据模型基于DOM
,文档是一个嵌套的树,其使用文本选区selections
和范围ranges
,并且公开所有的标准事件处理函数,这意味着像是表格或者是嵌套引用这样的高级特性是可能的,几乎所有你在DOM
中可以做到的事情,都可以在slate
中做到。slate
文档执行命令commands
来进行编辑,它被设计为高级并且非常直观地进行编辑和阅读,以便定制功能尽可能地具有表现力,这大大的提高了你理解代码的能力。slate
使用的数据模型特别是操作如何应用到文档上,被设计为允许协同编辑在最顶层,所以如果你决定要实现协同编辑,不必去考虑彻底重构。这样一段文本的数据结构如下所示。
[
{
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
是一个现代富文本编辑器,具备良好的兼容性及强大的可扩展性,还提供了部分开箱即用的功能。quill
是在2012
年开源的,quill
的出现给富文本编辑器带了很多新的东西,也是目前开源编辑器里面受众非常大的一款编辑器,至今为止的生态已经非常的丰富,可以在Github
等找到大量的示例,包括比较完善的协同实例。
在quill
的文档中有对于框架的设计原则上的描述:
API
驱动设计,quill
所有的功能都是通过API
来实现的并且可以直观的通过API
来获得数据的变化,以文本为中心的基础上构建的API
,不需要解析HTML
或者DIFF DOM
树,这样的设计可以让quill
的功能更加的灵活与更高的可拓展性。quill
公开了自己的文档模型,这是对DOM
的强大抽象,允许扩展和定制,由此数据结构的主角变成了Blots
、Parchment
、Delta
。quill
有着比较良好的兼容性,在旧版本的浏览器中也可以相同的方式运行,在用户体验上不同浏览器中也可以有着相同的视图与交互效果,并且可以在桌面和移动设备上使用。quill
携带了部分开箱即用的功能,如果不需要定制的话,这些功能已经足够了,同时quill
又有着非常高的可拓展性,用来自定义各种功能。这样一段文本的数据结构如下所示。
{
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
是用于在React
中构建富文本编辑器的框架,其为创建和自定义文本编辑器提供了强大的API
,并且旨在易于扩展和与其他库集成,与React
结合可以使开发者在进行编辑器开发时既不用操作DOM
、也不用单独学习一套构建UI
的范式,而是可以直接编写React
组件实现编辑器的UI
。draft
整体理念与React
非常的吻合,例如使用状态管理保存数据结构、使用immutable.js
库、数据结构的修改基本全部代理了浏览器的默认行为、通过状态管理的方式修改富文本数据等。
在draft
的README
中有对于框架的设计原则上的描述:
draft
无缝融入React
,使用React
用户熟悉的声明式的API
抽象出渲染、选择和输入行为的细节。draft
模型是使用immutable.js
构建的,提供具有功能状态更新的API
,并积极利用数据持久性来实现可扩展的内存使用。这样一段文本的数据结构如下所示。
{
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
。https://github.com/WindrunnerMax/EveryDay
https://github.com/hzjswlgbsj/blog
https://zhuanlan.zhihu.com/p/425265438
https://jkrsp.com/slate-js-vs-draft-js/
https://www.zhihu.com/question/404836496
https://www.zhihu.com/question/449541344
https://juejin.cn/post/6844903838982340622
https://juejin.cn/post/7034480408888770567
https://juejin.cn/post/6974609015602937870
https://github.com/cudr/slate-collaborative
https://blog.logrocket.com/what-is-slate-js-replace-quill-draft-js/
https://dev.to/charrondev/getting-to-know-quilljs---part-1-parchment-blots-and-lifecycle--3e76