前言
富文本编辑器在很多互联网领域被广泛应用,特别是各种Web端的程序,比如我们常用的电子邮件、社交平台、博客编辑平台等等。目前,有很多针对富文本编辑器的一些基本功能和拓展封装成一个开源的富文本编辑器,比如最开始百度的Ueditor
,现在比较流行的Quill
、BraftEditor
。对于一些简单的编辑功能,很多都是直接使用这些开源富文本编辑器的基础API,如果有其他的额外需求,还会在此基础上做一些拓展,而且这些开源的富文本编辑器都有开放的拓展API供我们使用。
那么这些富文本编辑器到底是如何实现的呢?
富文本编辑器介绍
富文本编辑器的基本结构通常是一个容器元素(例如 <div>
), 这个容器元素的 contenteditable
属性被设置为 true
,以允许用户对其内部的内容进行编辑。这个属性是实现富文本编辑器的基础。
富文本编辑器利用 JavaScript
的 DOM
操作来实现各种功能。编辑器通过获取编辑区域的 DOM
引用,并利用 DOM API
来操作文本内容和样式。
编辑器通常会附带一些工具栏,用于设置文本样式、插入图片等功能。这些功能会要处理各种用户交互,比如键盘输入、鼠标点击、文本选择等,需要通过为编辑器元素添加事件监听器,并在相应事件发生时执行特定的操作。
富文本编辑器可以将编辑区域内的 HTML 结构转换为其他格式,如纯文本、Markdown 等。这是为了适应不同的场景和需求,比如将编辑的文本内容保存到数据库、发送电子邮件等。
富文本编辑器最后输入的内容需要存储到后台,比如HTML字符串存储,后续获取进行编辑的时候也是拿到之前保存的HTML进行编辑器内部渲染。
光标位置和选择范围管理:富文本编辑器需要跟踪光标的位置以及用户的选择范围。这使得编辑器能够准确地应用样式和执行操作,比如插入链接、删除文本等。
总的来说,富文本编辑器其实就是HTML、CSS 和 JavaScript三者结合,只要好好使用这三样API,就能实现一个富文本编辑器。
要实现富文本编辑器需要了解哪些API
contenteditable
属性:该属性用于使元素可编辑。通过将其设置为"true",可以使元素具备编辑功能。
innerHTML
属性:这个属性用于获取或设置元素的 HTML 内容。通过读取或修改该属性,可以获取或更改编辑区域的内容。
execCommand()
方法:这个方法用于执行命令,比如设置字体样式、插入链接、插入图像等。使用该方法可以通过命令名称来执行编辑操作。例如:通过执行document.execCommand('bold')
,可以将选定的文本设置为粗体.
Selection
对象:这个对象提供了与文本选择相关的信息和操作。可以使用 Selection
对象获取光标位置、选择范围以及进行文本插入、删除等操作。
Range
对象:Range
对象表示文档中的一个范围区域,可以用于精确地控制选定的文本范围。它提供了一系列的方法和属性,可以进行文本选取、插入、删除等操作。
Selection对象
Selection 对象表示用户当前选择的文本范围,它提供了获取和操作选中文本的方法和属性。
属性和方法
anchorNode
: 返回当前选择范围的起始节点(节点可以是元素节点或文本节点)。
anchorOffset
: 返回当前选择范围的起始偏移量,即在 anchorNode 中的偏移位置。
focusNode
: 返回当前选择范围的结束节点。
focusOffset
: 返回当前选择范围的结束偏移量。
isCollapsed
: 判断当前选择范围是否是折叠的(即光标状态)。
removeAllRanges()
: 清除所有选择范围。
addRange(range)
: 添加一个 Range 对象到当前选择中。
toString()
: 返回选中文本的字符串表示。
Range对象
Range 对象表示文档中的一个范围区域,可以用于精确地控制选定的文本范围
属性和方法
startContainer
: 返回当前范围的起始节点(元素节点或文本节点)。
startOffset
: 返回当前范围在 startContainer 中的起始偏移量。
endContainer
: 返回当前范围的结束节点。
endOffset
: 返回当前范围在 endContainer 中的结束偏移量。
commonAncestorContainer
: 返回包含当前范围内所有节点的最深的共同祖先节点。
selectNode(node)
: 选中指定的节点。
selectNodeContents(node)
: 选中指定节点的内容。
setStart(startNode, startOffset)
: 设置范围的起始位置。
setEnd(endNode, endOffset)
: 设置范围的结束位置。
insertNode(node)
: 在当前范围内插入一个节点。
deleteContents()
: 删除当前范围内的内容。
Selection和Range在针对文本的相关操作是很有用的两个API,这里我主要是总结几个重要的一些属性和方法,具体的一些使用场景后续有机会再出一篇相关文章。
这种应用场景目前就有一个很好的例子:划线分享。简单说明一下,划线分享就是确定开始光标位置和结束位置,然后确定选定文本的范围,最后给选定的文本段设置一个特殊的样式区分显示,弹出对应的功能按钮分享。这里不就主要用Selection和Range嘛。
实现一个简单的富文本编辑器
创建编辑区域
首先需要一个编辑区域,创建一个div
元素,元素设置contenteditable=true
<div id="editor" contenteditable="true" style="border: 1px solid #ccc; min-height: 200px;"></div>
创建编辑功能Bar
其次,创建一个编辑器工具栏,我们就写一个最简单的,设置字体粗细。
<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>
function setFontStyle() {
const fontStyle = document.getElementById('fontStyle').value;
document.execCommand('fontName', false, fontStyle);
}
在 JavaScript 中,我们可以通过获取选中元素的值和编辑区域的引用,使用 document.execCommand()
方法来设置文本样式。
内容输出
通过一个按钮进行保存,保存的内容主要是通过innerHTML
拿到。
<button onclick="saveContent()">Save Content</button>
function saveContent() {
const editor = document.getElementById('editor');
const content = editor.innerHTML;
console.log(content); // 这里的内容可以通过后台接口保存到数据库中
}
以上其实就已经实现了一个特别简单基础的富文本编辑器,还有一部分比如一些媒体功能包括插入图片、插入视频等,可以按照上面一样的逻辑添加不同的功能。整体的实现思路大致就是这些。
但是实现过程中有需要注意的地方⚠️:
contenteditable=true
可编辑元素,默认回车会自动生成p
标签,但是不同浏览器的表现不一样,火狐和谷歌浏览器默认新建p
标签,safari默认新建div
标签,且第一个初始生成的p
标签会被砍掉只保留了文字部分。这里需要手动去创建一个特定的标签。
删除内容,需要注意删除到最后要保留之前初始化的空标签,不然会默认把初始化的空标签删掉,这样生成的html就不一致了。
最后
这次主要是介绍一下实现简单富文本编辑器的一个基础流程,其实他的核心就是contenteditable=true
,如果需要实现一个更好的富文本编辑器,就需要结合各个API进行事件处理和样式处理。目前也有好的开源富文本编辑器,我们可以参考他们的源码实现一个自己的富文本编辑器,这样不仅能够让自己对于一些API理解更深刻,而且关于一个完整的开源功能也有一个很好的认知。
作者:Betty97
链接:https://juejin.cn/post/7240751116702122021
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
该文章在 2023/12/28 11:00:34 编辑过