深入浅出QuillJS 第一节-QuillJS架构介绍

2,270 阅读4分钟

     QuillJS是一款强大的富文本编辑,具有很好的扩展性,有丰富便捷的api,可供使用。是一款轻量级,可二次开发的编辑器框架。适合任何复杂的定制场景。

一.为什么讲QuillJS

    由于公司的业务的需要, 需要寻找一款偏底层,好扩展的富文本编辑器,由于项目是基于react,所以首先考虑到的draftjs和slatejs 。 我们项目的需求特别复杂,draftjs应用起来总感觉性能不好,容易跳光标。slatejs感觉有些功能(拖拽)不太好实现,没有那么方便。
    最后我发现了QuillJS,做完一个项目后,更加坚定了我的选择,代码结构清晰,让人眼前一亮,虽然Quill初次使用,不太好理解,detla, blot,这些概念容易混淆。官方文档过于简单。 但源码就是最好的答案。 读完源码后,起初不太会用的东西,碰到很多坑,现在都可以理解了。 但不可否认,Quill也不是最完美的,还有很多可以改进的地方。所以将我的理解分享给大家,避免碰到一些弯路,过于简单的使用,我不会讲,大家可以去官方文档看,我会从源码的角度,讲比较深入的细节。涉及模块开发,怎么设计一个自定义的Module和Blot,怎么把React组件嵌入在QuillJS里面,怎么构建一个子编辑区域等等,如有说的不当之处,请大家指正,谢谢大家。

二.QuillJS架构简介

从以上图中可以看出主要构成有5大块,我从下到上这边分别介绍一下:

1.Core Class (核心类)

     这块主要是QuillJS的核心类,包含Selection光标处理,一些基类比如Mdeule模块管理的基类。emitter用于事件处理,处理quill的核心事件的定义比如editor-change,text-change的事件的定义,一个典型的pubSub模式。

** 2. Parchment(抽象文档模型) **

    Quill并没用使用浏览器的dom原有的文档模型。它自己抽象了一套基于dom的文档模型,Parchment由Blot组成,Blot有很多种纯文本的Blot是textBlot, 块级的是blockBlot,inlineBlot是内联的,可以被嵌套嵌套的,embedBlot是用于多媒体图片视频等等,并且每种Blot有自己的生命周期。Parchment被放在另一个git仓库中。后面会有一节单独讲Parchment。 

** 3. Modules(自带模块) **

    Quill还是给我们提供了一些基础模块,这些模块拿来即用。工具栏,表格,代码片段显示,剪切板,上传,键盘事件监听等等。拥有这些基本模块,其实不定制开发的话,就可以使用了。 

** 4. Blots(抽象文档实现)**

   Parchment这边定义blot的基础类,一些核心基类(ShadowBlot)和接口定义都在Parchment这边。具体Blots实现是在Quill这边。在Quill内做自定义开发,我们一般不直接操作Dom,都是通过blot去操作,blot里提供很多dom相似的方法和属性,比如parent(父节点),next(获取下一个节点),prev(上一个节点),appendChild添加子节点等等。他不是严格意义上的虚拟dom。每次操作更新只会影响当前的node节点。 

**5.Delta(Json文档数据上文描述) **

    它维护用户整个操作关系,虽然是一个扁平的json, 但他巧妙利用了attributes和插入顺序来描述结构关系。后面一节会细讲。下面是一个delta操作例子讲解:

const delta = new Delta().retain(7,{ bold:true })
	                 .retain(5)
	                 .insert('White', { color: '#fff' })
                         .delete(4);

retain(7,{ bold:null, italic:true})表示保留编辑器中索引为0 -7之间的blots, 并format样式加粗
retain(5) 保留编辑器中索引为0 -5之间的blots
insert('white', { color: '#fff' }) 表示接上一次操作后,插入文字'white', 并对其应用format 文字颜色为#fff
delete(4) 表示接上一个操作后,删除4个blots

delta操作有两层含义,第一可描述文档整个上下文关系,这样可以很好的回退和撤销。

从CoreClass中的history类里面的源代码可以看出

其中将delta源数据最后一位pop出后在做updateContents更新。
还有一层含义,就是通过quill的getContents方法,导出一份干净的json形式的Delta对象结构关系。可以存在mysql或mongo中,以便恢复和保存数据。

三,结语:

     本次文章,先抛个砖,下一节,我们讲一下parchment,以及blot的生命周期,和blot基本操作。还有源码跟踪blot整个结构是怎么样的。