12月5日,极客邦(InfoQ)在深圳举办GMTC大会,蚂蚁集团语雀编辑器技术同学三甲受邀参加大会并分享《在线富文本编辑器的架构设计及实践》,以下内容是根据现场演讲收集整理。
大家下午好,我叫韩聪,花名三甲。现在在蚂蚁集团语雀团队负责语雀文档编辑器的研发工作。
今天在这边和大家分享的是我们语雀在富文本编辑器上的架构设计和实践。
语雀编辑器家族首先,我们先来认识一下语雀的编辑器家族。语雀发展到现在我们已经诞生了7款类型不同的编辑器。老大是文档编辑器,它是基于传统的DOM技术来构建的,老二是目录编辑器,也是DOM技术来构建的。老三是工作表,他是基于Canvas构建的。老四和老五都是图类型的编辑器,他们是基于SVG技术来构建的。老六是演示文稿,也是SVG技术。
认识语雀文档编辑器今天和大家分享的是我们的老大——文档编辑器。先简单看一下这个文档编辑器的界面,是非常经典的一个布局,顶部是我们的工具栏区域,我们把一些常见的高频功能罗列出来放置于工具栏当中,供大家使用。
右侧是我们的功能扩展面板区域,这个区域常驻的是我们文档的大纲,根据用户的操作不同,这边还会出现其他的功能面板,比如图片设置面板以及附件下载控制面板。
中间是文档的编辑区域,这是我们编辑器工作的核心区域,编辑器下大部分的代码都是在处理这个区域上用户产生的交互。
这是语雀富本文编辑器填充后内容之后的一个效果。
富文本编辑器工作原理像这样的一个富文本编辑器,它背后的工作原理是什么呢?
其实在我的角度来看的话,我觉得其实只要清楚这两个问题就好了。第一个问题就是:在浏览器上我们如何去呈现富文本。第二个就是:在浏览器上我们如何去编辑富文本,我们来展开看一下
在浏览器上如何呈现富文本?首先我们需要先搞清楚什么是富文本,传统意义上的富文本其实是相对于纯文本的概念提出来的。简单来说就是具有丰富格式的文本。
回到这个问题本身,我们怎么去在浏览器上去呈现这些内容呢?那就必然离不开这个浏览器的内容呈现技术。浏览器为我们提供的内容呈现技术大致上有3种:SVG、Canvas和HTML+CSS。
这三种技术我们到底应该选哪一种来呈现我们的富文本呢?我给出的答案是HTML+CSS,为什么呢?因为它足够简单,另外它的扩展非常方便。通常情况下,我们要实现相同的UI效果的话,HTML+CSS是这三种技术中最简单的一个,它所需要的代码是最少的。
如何在浏览器上如何编辑富文本?接着,我们来看看第二个问题,怎么去编辑富文本呢?搞清楚这个问题,基本上编辑器神奇的面纱就被揭掉了。对于现在的这些编辑器来说,大部分人的答案都是contenteditable。
contenteditable是一个HTML属性,它可以让一个DOM元素变成可编辑的。这种能力,就很适合用来构建我们的富文本编辑器。我们所需要做的就是找到我们的编辑器,把我们这个编辑器的根节点,挂上这个属性,然后开启编辑状态就好了。同时在一个元素变成可编辑的时候,浏览器还会帮我们去处理好选区和光标移动这样的一些基础功能。
那到了这里,我们把两个问题都已经回答清楚之后,其实整个编辑器,对于我们前端同学来说,就没有什么太大的技术壁垒了。剩下要做的就是按部就班的地去实现编辑器的功能。这一部分就是我们对这个富文本编辑器的工作原理的一个简单阐述。
语雀文档编辑器下个环节我们就开始进入到语雀的文档编辑器,去了解一下语雀的文档编辑器背后的这个架构是怎么设计的,是怎么去实现的?
语雀文档编辑器演进历程首先我们先看一下语雀编辑器的发展历程。语雀从诞生到现在已经经历了持续了应该有六年左右,期间经历过四代的编辑器升级。
年第一代编辑器,它是一个markdown编辑器,还不属于一个富本编辑器。我们是基于CodeMirror二次开发的。这时候我们主要服务的对象是我们内部的工程师同学。
到了年,我们进入了富文本编辑器的时代。第二代的编辑器我们是基于Slate.js进行二次开发的。
年,我们的第三代编辑器推出上线了。这一代编辑器是我们自研的,它的工作原理就是我刚才提到的这个contenteditable。第三代编辑器是我们目前为止线上运行时间最长的编辑器,总共在线上待了有快三年的时间,直到今年的四月份才被我们的第四代编辑器给取代掉。第四代编辑器底层技术也是contenteditable,但是它是一个基于微内核思想来重新设计的。
我们今天要重点讲的就是第四代编辑器,然后我们也是顺带会提一下第三代编辑器。第一代和第二代我们就不在这讲了,因为时间太久远了。
第三代文档编辑器第三代文档编辑器架构我给你们先看一下第三代编辑器。这是第三代编辑器的一个架构,它主要由两部分组成。第一部分会负责UI的创建和管理。这里面典型的一些就是我们工具栏侧边栏这样的一些东西。然后第二部分是一个被称为Engine的编辑引擎。这里面会完成所有富文本的编辑工作,它由一个被称为Core的内核和一系列的插件构成。通过这种插件和我们的内核共同协作的方式,我们就一起完成了整个编辑器的核心——富文本编辑功能。这是第三代编辑的一个架构。
文档初始化流程接着是第三代编辑器的一个文档初始化流程。整个流程非常简单,就是当我们的编辑器收到了初始化请求之后,它会对这个内容进行一次解析,把它转换成我们的DOM树,然后再把这个DOM树进行一些转换。转换的目的是会把一些具有相同语义或者相同标签归一化成同一个标签,这样的用途就是为了简化我们后续的算法实现,使得它们可以