实现一个富文本编辑器是一个复杂的项目,涉及到前端和后端的多个方面。以下是一个简化的实现方案,我们将使用HTML、CSS和JavaScript来构建一个基本的富文本编辑器。### 1. HTML结构首先,我们需要一个容器来放置编辑器:```htmlRich
摘要:在先前的规划中我们是需要实现MVC架构的编辑器,将应用程序分为控制器、模型、视图三个核心组件,通过控制器执行命令时会修改当前的数据模型,进而表现到视图的渲染上。简单来说就是构建一个描述文档结构与内容的数据模型,并且使用自定义的execCom
在先前的规划中我们是需要实现MVC架构的编辑器,将应用程序分为控制器、模型、视图三个核心组件,通过控制器执行命令时会修改当前的数据模型,进而表现到视图的渲染上。简单来说就是构建一个描述文档结构与内容的数据模型,并且使用自定义的execCommand对数据描述模型进行修改。以此实现的L1级富文本编辑器,通过抽离数据模型,解决了富文本中脏数据、复杂功能难以实现的问题。
开源地址: https://github.com/WindRunnerMax/BlockKit
在线编辑: https://windrunnermax.github.io/BlockKit/
项目笔记: https://github.com/WindRunnerMax/BlockKit/blob/master/NOTE.md
从零实现富文本编辑器项目的相关文章:
深感一无所长,准备试着从零开始写个富文本编辑器
从零实现富文本编辑器#2-基于MVC模式的编辑器架构设计
从零实现富文本编辑器#3-基于Delta的线性数据结构模型
精简的编辑器
在整套系统架构的设计中,最重要的核心理念便是状态同步,如果以状态模型为基准,那么我们需要维护的状态同步就可以归纳为下面的两方面:
将用户操作状态同步到状态模型中,当用户操作文本状态时,例如用户的选区操作、输入操作、删除操作等,需要将变更操作到状态模型中。
将状态模型状态同步到视图层中,当在控制层中执行命令时,需要将经过变更后生成的新状态模型同步到视图层中,保证数据状态与视图的一致。
其实这两个状态同步是个正向依赖的过程,用户操作形成的状态同步到状态模型,状态模型的变更同步到视图层,视图层则又是用户操作的基础。举个例子,当用户通过拖拽选择部分文本时,需要将其选中的范围同步到状态模型。当此时执行删除操作时,需要将数据中的这部分文本删除,之后再刷新视图的到新的DOM结构。下次循环就需要继续保证状态的同步,然后执行输入、刷新视图等操作。
由此我们的目标主要是状态同步,虽然看起来仅有简单的两个原则,但是这件事做起来并没有那么简单。当我们执行状态同步时,是非常依赖浏览器的相关API的,例如选区、输入、键盘等事件。然而此时我们必须要处理浏览器的相关问题,例如截止目前ContentEditable无法真正阻止IME的输入,EditContext的兼容性也还有待提升,这些都是我们需要处理的问题。
实际上当我们用到了越多的浏览器API实现,我们就需要考虑越多的浏览器兼容性问题。因此富文本编辑器的实现才会出现很多非ContentEditable的实现,例如如钉钉文档的自绘选区、Google Doc的Canvas文档绘制等。但是这样虽然能够降低部分浏览器API的依赖,但是也无法真正完全脱离浏览器的实现,因此即使是Canvas绘制的文档,也必须要依赖浏览器的API来实现输入、位置计算等等。
回到我们的精简编辑器模型,先前的文章已经提到了ContentEditable属性以及execCommand命令,通过document.execCommand来执行命令修改HTML的方案虽然简单,但是很明显其可控性比较差。execCommand命令的行为在各个浏览器的表现是不一致的,这也是之前我们提到的浏览器兼容行为的一种,然而这些行为我们也没有任何办法去控制,这都是其默认的行为。
<div>
<button id="$1">加粗</button>
<div style="border: 1px solid #eee; outline: none" contenteditable>123123</div>
</div>
<script>
$1.onclick = () => {
document.execCommand("bold");
};
</script>
因此为了更强的扩展以及可控性,也解决数据与视图无法对应的问题,L1的富文本编辑器使用了自定义数据模型的概念。即在DOM树的基础上抽离出来的数据结构,相同的数据结构可以保证渲染的HTML也是相同的,配合自定义的命令直接控制数据模型,最终保证渲染的HTML文档的一致性。对于选区的表达,则需要根据DOM选区来不断normalize选区Model。
这也就是我们今天要聊的MVC模型架构,我们组织编辑器项目是通过monorepo的形式来管理的相关包,这样就自然而然地可以形成分层的架构。不过在此之前,我们可以在HTML文件中实现最基准的编辑器 simple-mvc.html,当然我们还是实现最基本的加粗能力,主要关注点在于整个流程的控制。
