实现一个富文本编辑器是一个复杂的项目,涉及到前端和后端的多个方面。以下是一个简化的实现方案,我们将使用HTML、CSS和JavaScript来构建一个基本的富文本编辑器。### 1. HTML结构首先,我们需要一个容器来放置编辑器:```htmlRich
摘要:先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区,编辑器中应用变更时的操作范围,就是以模型选区为基准来实现的。在这里我们就以编辑器状态为
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区,编辑器中应用变更时的操作范围,就是以模型选区为基准来实现的。在这里我们就以编辑器状态为基础,来设计模型选区的结构表达。
开源地址: https://github.com/WindRunnerMax/BlockKit
在线编辑: https://windrunnermax.github.io/BlockKit/
项目笔记: https://github.com/WindRunnerMax/BlockKit/blob/master/NOTE.md
从零实现富文本编辑器项目的相关文章:
深感一无所长,准备试着从零开始写个富文本编辑器
从零实现富文本编辑器#2-基于MVC模式的编辑器架构设计
从零实现富文本编辑器#3-基于Delta的线性数据结构模型
从零实现富文本编辑器#4-浏览器选区模型的核心交互策略
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
编辑器选区模型
在编辑器中的选区模型设计是涉及面比较广的命题,因为其作为应用变更或者称为执行命令的基础范围,涉及到了广泛的模块交互。虽然本质上是需要其他模块需要适配选区模型的表达,但明显的如果选区模型不够清晰的话,其他模块的适配工作就会变得复杂,交互自然是需要相互配合来实现的。
而选区模型最直接依赖的就是编辑器的状态模型,而状态模型的设计又非常依赖数据结构的设计。因此,在这里我们会从数据结构以及状态模型的角度出发,先来调研一下当前主流编辑器的选区模型设计。
Quill
Quill是一个现代富文本编辑器,具备良好的兼容性及强大的可扩展性,还提供了部分开箱即用的功能。Quill的出现给富文本编辑器带了很多新的东西,也是目前开源编辑器里面受众非常大的一款编辑器,至今为止的生态已经非常的丰富,目前也推出了2.0版本。
Quill的数据结构表达是基于Delta实现的,当然既然其名为Delta,那么数据的变更也可以基于Delta来实现。那么使用Delta表达基本的富文本数据结构如下所示,可以观察到其不会存在嵌套的数据结构表达,所有内容以及格式表达都是线性的。
{
ops: [
{ insert: "这样" },
{ insert: "一段文本", attributes: { italic: true } },
{ insert: "的" },
{ insert: "数据结构", attributes: { bold: true } },
{ insert: "如下所示。\n" },
],
};
既然数据结构是扁平的表达,那么选区的表达也不需要复杂的结构来实现。直观感受上来说,扁平化结构要特殊处理的Case会更少,状态结构会更好维护,编辑器架构会更加轻量。通常编辑器的选区也会构造Range对象,那么在Quill中的选区结构如下所示:
{
index: 5, // 光标位置
length: 10, // 选区长度
}
选区作为编辑器变更的应用范围,不可避免地需要提及应用变更的操作。在应用变更时,自然需要进行状态结构的遍历,以取出需要变更的节点来实际应用变更。那么自然而然地,扁平的结构本身的顺序就是渲染的顺序,不需要嵌套的结构来进行递归地查找,查找的效率自然会更高。
此外,Quill的视图层是重新设计了一套模型parchment,维护了视图和状态模型,虽然在仓库中通过继承的方式重写了部分类结构,例如ScrollBlot类。但是在阅读源码的时候难以确定很多视图模块设计意图,所以对于DOM事件与状态模型的交互暂时还没有很好的理解。
Slate
Slate是一个高度灵活、完全可定制的富文本编辑器框架,其提供了一套核心模型和API,让开发者能够深度定制编辑器的行为,其更像是富文本编辑器的引擎,而不是开箱即用的组件。Slate经历过一次大版本重构,虽然目前仍然处于Beta状态,但是已经有相当多的线上服务使用。
Slate的数据结构表达就不是扁平的内容表示的,依据其TS类型的定义,Node类型是Editor | Element | Text三种类型的元组。当然抛开Editor本身不谈,我们从下面的内容描述上可以很容易看出来Element和Text类型的定义。
