节点:编辑器,元素和文本

最重要的类型是 Node 对象:

  • 包含整个文档内容的 Editor 根节点。
  • 在自定义域中拥有语义的 Element 容器节点。
  • 包含文档文本的 Text 叶子节点。

这三个接口组合在一起形成一棵树 — 就像 DOM 一样。举例来说,这是一个简单的纯文本值:

  1. const editor = {
  2. children: [
  3. {
  4. type: 'paragraph',
  5. children: [
  6. {
  7. text: 'A line of text!',
  8. },
  9. ],
  10. },
  11. ],
  12. // 编辑器还有被省略的其他属性。
  13. }

尽可能地对应 DOM 是 Slate 的原则之一。人们总是使用 DOM 来描述类似富文本结构的文档。对应 DOM 有助于新用户熟悉类库,并且可以让我们重用经过重重考验的结构模式,而不是自己造一个新的轮子。

🤖 下面来自于 MDN Web 文档 的内容可以帮助你理解更多相应的 DOM概念:

Slate 文档是一个嵌套递归的结构。在文档中,元素可以有子节点 — 所有元素都可以无限制地拥有子节点。嵌套递归的结构确保你可以建模简单的行为,比如用户的 @提及 和 # 标签或是带标题的表格和图片。

编辑器: Editor

Slate 的顶级节点就是 Editor 。它封装了文档的所有富文本内容。它的接口是这样的:

  1. interface Editor {
  2. children: Node[]
  3. ...
  4. }

我们稍后会介绍他的功能,但是对于节点来说最重要的部分是它的 children 属性,其中包含一个 Node 对象树。

元素:Element

元素组成了富文本文档的中间层。它们是对你的域定制的节点。它们的接口是这样的:

  1. interface Element {
  2. children: Node[]
  3. [key: string]: any
  4. }

你可以为任何类型的内容定义自定义元素。比如你可能想要一个段落和引用在你的数据模型中,它们通过 type 属性区分:

  1. const paragraph = {
  2. type: 'paragraph',
  3. children: [...],
  4. }
  5. const quote = {
  6. type: 'quote',
  7. children: [...],
  8. }

需要提醒的是,你可以使用任何的自定义属性。在这个例子中, Slate 并不关心 type 属性具体是什么。如果你自定义了 “link” 节点,你可能有一个 url 属性:

  1. const link = {
  2. type: 'link',
  3. url: 'https://example.com',
  4. children: [...],
  5. }

或者你可能给所有的节点定义一个 ID 属性:

  1. const paragraph = {
  2. id: 1,
  3. type: 'paragraph',
  4. children: [...],
  5. }

重要的是元素总是有一个 children 属性。

块(Blocks)和行内(Inlines)

根据你的用例,你可能想要为 Element 定义一个另一个行为,这个行为决定了它的编辑流。

所有元素默认是块元素。它们被垂直空间隔开,并且永不重叠。

但是在某些情况下,比如链接,你可能想要把它作为行内元素流。 这样的话,它就会和文本节点位于同一级别和同样的流。

🤖 这个概念借用了 DOM 的行为,参考 块级元素行内元素

可以通过重写 editor.isInline 函数来定义哪些节点属于行内节点。(默认情况下,它总是返回false。)

元素可以将块元素作为子元素包含。或者混合行内元素和文本元素,把它们作为子节点。但是元素不能同时包含行内元素和块元素。

空元素(Voids)

类似于块元素和行内元素,另一个你可以定义的特殊元素为空元素:它们的 “void” 性:

元素默认是非空元素,意味着它的子元素是完全可以像文本一样编辑。但是有时候,比如图像, 你可能想要确保 Slate 不会将元素的内容作为可编辑的文本,而是看做一个黑箱。

🤖 这个概念是从 HTML 借用的,请查看 空元素

可以通过定义 editor.isVoid 函数来定义哪些元素被视为 void。(默认情况下,它总是返回false。)

文本:Text

文本节点是树中的最低级节点,包含文档的文本内容以及任何格式。它的接口是:

  1. interface Text {
  2. text: string
  3. [key: string]: any
  4. }

比如这个例子,加粗文本:

  1. const text = {
  2. text: 'A string of bold text',
  3. bold: true,
  4. }

文本节点可以包含任意的自定义属性,这就是你如何实现像是粗体斜体代码等自定义格式的办法。