一个Level 0富文本编辑器的进化历程

727次阅读  |  发布于7月以前

一个Level 0富文本编辑器的进化历程

富文本编辑器是我们在生活中常用到的编辑工具,本文将为大家介绍富文本编辑器技术成长的历程,在最后会带大家利用document.execCommand实现一个简单的传统编辑器。

ps:document.execCommand 是实现富文本编辑器的核心 API 。但遗憾的是 document.execCommand 已经被 MDN 给废弃了。而且,一直以来,各个浏览器对于它的实现,细节上也没有完全统一,浏览器兼容性一直比较头疼。本文仅作富文本编辑器的简单探究。

编辑器技术阶段划分

通常大家把编辑器技术分为三个阶段

Level 0 第一阶段,是编辑器的起始阶段,代表旧一代的编辑器的实现

主要依赖于浏览器原生的编辑能力,用户内容的输入是浏览器直接处理,加粗、斜体、回车等这类的处理则是捕获浏览器的事件来覆盖浏览器默认行为来实现,再辅以一些DOM的嵌套规则和复杂数据输入(如粘贴)的过滤规则来约束数据的正确性,这类编辑器整体思路还是比较清晰的。

虽然基于浏览器原生编辑能力,输入非常流畅,但是不可以预测的交互,容易出现数据混乱(拖拽、复制粘贴、删除)。相同操作不同浏览器可能有不同的实现(比如基本的加粗、斜体、Enter),很难实现表现和数据完全统一。

Level 1 第二阶段,是在第一阶段发展过来的,有一定的先进性,也引入了主流的一些编程思想,对于富文本内容有一定的抽象

这个时期的富文本编辑器的底层还是依赖原生DOM的contentEditable特性,但是他们对DOM Tree以及数据的修改操作进行了抽象,抽象出了数据变化的操作。这意味着编辑器开发者大部分场景下其实不是直接通过修改DOM完成编辑器功能的,他们通过捕获用户的操作行为,将原有的修改dom调整为操作API修改数据模型,再将更新后的状态映射至视图,来实现编辑器的所见即所得的效果。输出数据可以是HTML的字符串,也可能是自己嵌套的文档模型(JSON)。

Level 2 第三阶段,完全不依赖浏览器的编辑能力,独立的实现光标和排版

早在2010年Google Doc就使用了全新的技术来实现富文本编辑器,实现了自己的富文本编辑 API ,就是大家通常说的第三阶段(Level 2),不使用Contenteditable,可以实现文本的独立排版,不再依靠浏览器的任何编辑功能,自主实现选区光标和内容排版,只不过目前还没有一款基于这套架构的开源技术。

从Level 0到Level 2,个人理解就是将富文本编辑器的控制权一步步由浏览器控制,变成由开发者控制者。

具体实现一个传统的简单编辑器

传统的富文本编辑器中内容的可编辑主要依赖DOM的contentEditable属性,基于原生execCommand或者自定义扩展的execCommand去操作DOM实现富文内容的修改。

当一个HTML文档切换到设计模式(designMode)时,文档对象暴露 execCommand方法,该方法允许运行命令来操纵可编辑区域的内容。大多数命令影响文档的选择(粗体,斜体等),而其他命令插入新元素(添加链接)或影响整行(缩进)。当使用 contentEditable时,调用 execCommand() 将影响当前活动的可编辑元素。

要实现富文本编辑器需要了解哪些API

contenteditable 属性:该属性用于使元素可编辑。通过将其设置为"true",可以使元素具备编辑功能。  

innerHTML 属性:这个属性用于获取或设置元素的 HTML 内容。通过读取或修改该属性,可以获取或更改编辑区域的内容。   

execCommand() 方法:这个方法用于执行命令,比如设置字体样式、插入链接、插入图像等。使用该方法可以通过命令名称来执行编辑操作。
语法:execCommand(aCommandName, aShowDefaultUI, aValueArgument)
参数:
aCommandName:指定要执行的命令名称的字符串。
aShowDefaultUI:一个布尔值,指示是否应显示默认用户界面。Mozilla 中未实现此功能。
aValueArgument:对于需要输入参数的命令,是提供该信息的字符串。例如,insertImage需要插入图像的 URL。指定null是否不需要参数。
例如:通过执行document.execCommand('bold'),可以将选定的文本设置为粗体.

Selection 对象:Selection 对象表示用户当前选择的文本范围,可以使用 Selection 对象获取光标位置、选择范围以及进行文本插入、删除等操作。

Range 对象:Range 对象表示文档中的一个范围区域,可以用于精确地控制选定的文本范围。它提供了一系列的方法和属性,可以进行文本选取、插入、删除等操作。

创建编辑区域

首先需要一个编辑区域,创建一个div元素,元素设置contenteditable=true

<!-- HTML -->
<div id="editor" contenteditable="true" style="border: 1px solid #ccc; min-height: 200px;"></div>

创建一个编辑器控制栏

编辑器控制栏,用于对文本进行各种控制修改,我们就写一个最简单的,设置字体倾斜。上面有介绍,在 JavaScript 中,我们可以使用 document.execCommand() 方法来设置文本样式。

<!-- HTML -->
 <select id="fontStyle">
    <option value="normal">Normal</option>
    <option value="bold">Bold</option>
    <option value="italic">Italic</option>
  </select>
  <button onclick="setFontStyle()">Set Style</button>

<!--  JS -->
function setFontStyle() {
  const fontStyle = document.getElementById('fontStyle').value;
  document.execCommand(fontStyle, false, null);
}

内容输出

保存的内容主要是通过innerHTML拿到。

function saveContent() {
  const editor = document.getElementById('editor');
  const content = editor.innerHTML;
  console.log(content); // 输出富文本内容是HTML字符串
}

以上就实现了一个特别简单基础的富文本编辑器。

结语

目前,有很多针对富文本编辑器的一些基本功能和拓展封装成一个开源的富文本编辑器,比如最开始百度的Ueditor,比较流行的Quill、Slate,基本都是实现了自己的contentEditable,抛弃了对浏览器原生的contentEditable特性的依赖。在我们平时开发过程中,对于一些简单的编辑功能,可以直接使用这些开源富文本编辑器的基础API,并且在此基础再做扩展。

参考文章

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8