Skip to content

Commit

Permalink
25/01/18
Browse files Browse the repository at this point in the history
  • Loading branch information
WindRunnerMax committed Jan 18, 2025
1 parent 99316f2 commit f4cb9ff
Showing 1 changed file with 49 additions and 7 deletions.
56 changes: 49 additions & 7 deletions Backup/从零设计实现富文本编辑器.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,27 +200,68 @@ export interface Op {
}]
```

扁平的数据结构在数据处理方面会存在优势,而在视图层面上,扁平的数据结构表达结构化的数据会是比较困难的,例如表达代码块、表格等嵌套结构。但是这件事并非是不可行的,例如`Google Doc`的复杂表格嵌套就是完全的线性结构,这其中是存在很巧妙的设计在里边的。
扁平的数据结构在数据处理方面会存在优势,而在视图层面上,扁平的数据结构表达结构化的数据会是比较困难的,例如表达代码块、表格等嵌套结构。但是这件事并非是不可行的,例如`Google Doc`的复杂表格嵌套就是完全的线性结构,这其中是存在很巧妙的设计在里边的,在这里先不展开了

最后还是有协同相关的实现,协同算法是富文本编辑器的可选模块。无论是基于`OT`的协同算法,还是`Op-Based CRDT`的协同算法,都是需要传输上述的`op`类型与数据的,那么很显然`9`种操作的`op`类型会比`3`种操作的`op`类型更加复杂。

- [OT.js: Text 数据类型](https://github.com/Operational-Transformation/ot.js/blob/e9a3a0e/lib/text-operation.js#L39)
- [ShareDB Rich-Text: Delta OT 数据类型](https://github.com/ottypes/rich-text/tree/b53cd97)
- [ShareDB JSON0: JSON OT 数据类型](https://github.com/ottypes/json0/tree/90a3ae)
- [ShareDB Slate: Slate OT 数据结构适配器](https://github.com/pubuzhixing8/ottype-slate/tree/f88274)
- [YJS YText: Delta 数据类型实现](https://github.com/yjs/yjs/blob/4b8657/src/types/YText.js)
- [YJS YMap/YArray: JSON 数据类型实现](https://github.com/yjs/yjs/blob/4b8657/src/types/)
- [YJS Slate: Slate 数据结构适配器](https://github.com/BitPhinix/slate-yjs/tree/69f3e0e/packages/core/src/applyToYjs)

因此,我希望能够以线性的数据结构来实现整个编辑器结构,这样`quill``delta`就是非常好的选择。但是`quill`是自行实现的视图层结构,并非是可以组合`react`等视图层的形式,组合这些视图层的优势就是可以直接使用组件库样式来实现编辑器,而避免了每个组件都需要自行实现。那么这里我准备基于`quill`的数据结构,来从零实现富文本编辑器核心层,并且像`slate`一样以此组合基本的视图层。

## 方案选型
实现`ContentEditable`的编辑器
其实这里有个有趣的问题,为什么用不到`1mb`的代码量就可以实现部分类似`office word`编辑器的能力,是因为浏览器已经帮我们做了很多事情,并通过`API`提供给开发者,包括输入法处理、字体解析、排版引擎、视图渲染等等。

因此我们是需要设计出如何跟浏览器交互的方案,毕竟我们实际上是需要跟浏览器交互的。而对于富文本编辑器最经典的描述则是分为了三级:

- `L0`: 基于浏览器提供的`ContentEditable`实现富文本编辑,使用浏览器的`document.execCommand`执行命令操作。 是作为早期轻量编辑器,可以较短时间内快速完成开发,但可定制的空间非常有限。
- `L1`: 同样基于浏览器提供的`ContentEditable`实现富文本编辑,但数据驱动可以自定义数据模型与命令的执行。常见的实现有语雀、飞书文档等等,可以满足绝大部分使用场景,但无法突破浏览器自身的排版效果。 |
- `L2`: 基于`Canvas`自主实现排版引擎,只依赖少量的浏览器`API`。常见的实现有`Google Docs`、腾讯文档等等,具体实现需要完全由自己控制排版,相当于使用画板而不是`DOM`来绘制富文本,技术难度相当高。

实际上在目前的开源产品中,这三种类型的编辑器都有涉及到,特别是绝大多数开源的都是`L1`类型的实现。而这其中还分化了不依赖`ContentEditable`却也不是完全自绘引擎,而是依赖`DOM`呈现内容外加自绘选区的实现,实际上倒是可以算作`L1.5`的级别。

本着学习的目的,自然要选择开源产品多的实现,这样遇到问题可以更好地借鉴和分析相关内容。因此我同样打算选择基于`ContentEditable`,实现数据驱动的标准`MVC`模型的富文本编辑器,基于这种方式来与浏览器交互,实现基本的富文本编辑能力。在此之前,我们还是先了解一下基本的编辑器实现:

### execCommand
<div contenteditable></div>
如果我们仅仅需要最基本的行内样式,例如加粗、斜体、下划线等,这可能在一些基本输入框中是足够的,那么我们自然可以选择使用`execCommand`来实现。甚至直接基于`execCommand`的好处就是,其体积会非常小,例如[pell](https://github.com/jaredreich/pell)的实现,仅仅需要`3.54KB`的代码体积。

```plain
data:text/html,<div contenteditable style="border: 1px solid black"></div>
我们也可以实现可以加粗的最小`DEMO``execCommand`命令可以在`contenteditable`元素中选区内的元素执行,`document.execCommand`方法接受三个参数,分别是命令名称、显示用户界面、命令参数。显示用户界面一般都是`false``Mozilla`没有实现,而命令参数则是可选的,例如超链接命令则需要传递具体链接地址。

```html
<div>
<button id="$1">加粗</button>
<div style="border: 1px solid #eee; outline: none" contenteditable>
123123
</div>
</div>
<script>
$1.onclick = () => {
document.execCommand("bold");
};
</script>
```
https://github.com/jaredreich/pell

当然,这个示例过于简单,我们还可以在选区变换的时候,来判断加粗按钮的加粗状态,以此来显示当前选区状态。不过我们需要对齐`execCommand`的命令行为,前边也提到了可控性非常差,因此我们需要通过`document.createTreeWalker`迭代所有的选区节点,以此来判断当前选区的状态。

其实这里还需要注意的是,`execCommand`命令的行为在各个浏览器的表现是不一致的,这也是之前我们提到的浏览器兼容行为的一种,然而这些行为我们也没有任何办法去控制,这都是其默认的行为:

- 在空`contenteditable`编辑器的情况下,直接按下回车键,在`Chrome`中的表现是会插入`<div><br></div>`,而在`Firefox(<60)`中的表现是会插入`<br>``IE`中的表现是会插入`<p><br></p>`
-


### ContentEditable

### Canvas
```text
data:text/html,<div contenteditable style="border: 1px solid black"></div>
```

### Canvas
排版引擎

## 每日一题

Expand All @@ -232,6 +273,7 @@ https://github.com/jaredreich/pell
- <https://zhuanlan.zhihu.com/p/407713779>
- <https://zhuanlan.zhihu.com/p/425265438>
- <https://zhuanlan.zhihu.com/p/259387658>
- <https://zhuanlan.zhihu.com/p/145605161>
- <https://www.zhihu.com/question/38699645>
- <https://www.zhihu.com/question/404836496>
- <https://juejin.cn/post/6974609015602937870>
Expand Down

0 comments on commit f4cb9ff

Please sign in to comment.