实现一个富文本编辑器是一个复杂的项目,涉及到前端和后端的多个方面。以下是一个简化的实现方案,我们将使用HTML、CSS和JavaScript来构建一个基本的富文本编辑器。### 1. HTML结构首先,我们需要一个容器来放置编辑器:```htmlRich
摘要:先前我们实现了内容更新时性能的优化,考虑了最小化Op操作DOM变更、key值的维护、以及在React中实现增量渲染的方式。那么接下来我们需要讨论的是编辑节点的组件预设,例如零宽字符、Embed节点、Void节点等,为编辑器的插件扩展提供预设
先前我们实现了内容更新时性能的优化,考虑了最小化Op操作DOM变更、key值的维护、以及在React中实现增量渲染的方式。那么接下来我们需要讨论的是编辑节点的组件预设,例如零宽字符、Embed节点、Void节点等,为编辑器的插件扩展提供预设默认行为的组件。
开源地址: 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-编辑器选区模型的状态结构表达
从零实现富文本编辑器#6-浏览器选区与编辑器选区模型同步
从零实现富文本编辑器#7-基于组合事件的半受控输入模式
从零实现富文本编辑器#8-浏览器输入模式的非受控DOM行为
从零实现富文本编辑器#9-编辑器文本结构变更的受控处理
从零实现富文本编辑器#10-React视图层适配器的模式扩展
从零实现富文本编辑器#11-Immutable状态维护与增量渲染
从零实现富文本编辑器#12-React可编辑节点的组件预设
概述
富文本编辑器之所以被称为富文本,除了其能够支持文本的格式化之外,还能够支持插入图片、视频、Mention等内容。而最开始我们就提到了,实现受控的编辑器是需要严格设计DOM结构的,以便于能够正确查找和操作这些节点,因此支持这些节点仍然需要需要预设DOM结构。
然而诸如图片等节点是需要交由开发者自定义实现的,因此这里的DOM结构在编辑器框架层面上是完全不可控的,因此我们需要约定好针对不同类型的组件嵌套不同的HOC组件,以此来处理默认的DOM结构以及行为。例如下面这个组件就固定了最外层的结构,开发者只需要使用即可。
export const HOC: FC = () => {
return (
<div onMouseDown={defaultBehavior}>
<span>{"\u200B"}</span>
<div contentEditable={false}>
<img src={src} alt={alt} />
</div>
</div>
);
}
此外还有非文本节点选区问题,通常情况下选区都是在文本节点上的,也就是说通过Selection对象取得的节点是text类型节点。然而在某些情况下,会存在非文本节点的选区,例如在三击文本行的时候,会出现整行的选区,此时会出现anchor节点是行首text节点,而focus节点是下一行的行节点。
{
anchorNode: text,
anchorOffset: 0,
focusNode: div, // <div data-node="true">...</div>
focusOffset: 0,
}
类似这种情况就需要进行校正,将选区校正到文本类型节点上。特别需要注意此时的focus节点是下一行的节点,因此我们需要校正的目标是下一行行首文本节点offset: 0的位置,因此这样的Model选区就可以对应为选区两行的0 offset位置,同时需要同步到DOM选区上。
编辑器实现的查找逻辑基本上参考了slate的实现,大概目标是尝试找到可编辑子节点,首先会调用getEditableChildAndIndex查找一级子节点,相当于先查找一级来判断后续迭代方向。之后继续查找,这里是采取的DFS搜索形式,查找每一级都会尝试找到可编辑节点。
这里有必要提一下,其实在上一篇文章中处理完增量变更之后,接下来需要考虑输入内容时避免预设DOM的结构被破坏的问题,包括本文预设的组件也需要处,主要涉及脏DOM检查、选区更新、渲染Hook等。但这部分内容在#8和#9的输入法处理中已经有了详细的讨论,因此这里就不再次展开了。
零宽字符
零宽字符顾名思义是没有宽度的字符,因此就很容易推断出这些字符在视觉上是不显示的。因此这些字符就可以作为不可见的占位内容,实现特殊的效果。
