# 理解文档模型

认识节点、格式和 Schema，为文章或 Word 文档选择内容结构。

上一章把 HTML 传给 `content`，编辑器显示出一段文字。但 Core 内部保存的并不是页面截图，也不是一段随意拼接的 HTML，而是一棵描述内容的文档树。

## 一段文字怎样成为文档

例如“你好，QuireKit”是一段正文，它的 JSON 表示如下：

```json [一段正文]
{
  "type": "doc",
  "content": [
    {
      "type": "paragraph",
      "content": [{ "type": "text", "text": "你好，QuireKit" }]
    }
  ]
}
```

`doc` 是整份文档，`paragraph` 是段落，`text` 是文字。它们都是节点（Node）。粗体、斜体和链接这类附着在文字上的格式叫标记（Mark），保存在文字节点的 `marks` 中。标题级别等额外信息则放在节点的 `attrs` 中。

这种结构让同一份内容可以被命令修改、撤销、保存，也可以交给不同视图显示。文字在哪一页、选区画在哪个像素位置，属于后续排版和显示的结果。

## Schema 决定允许哪些内容

Schema 可以理解为这份文档的结构规则：能否出现标题？列表里允许什么内容？文字可以加哪些格式？Core 根据安装的 Node 和 Mark 扩展生成这些规则。

上一章安装的 StarterKit 已经包含段落、标题、列表和常见格式，因此不需要自己编写这些定义。新增一种内容，例如“提示组”，才需要新增 Node；[内容扩展](/build/extension)会带你实现它。

恢复旧文档时也必须安装对应扩展。否则编辑器不知道未知节点的含义，不能把它当成普通段落悄悄丢掉。

## 先选择文章还是 Word 文档

| 你的产品需要什么 | 从哪种组合开始 | 需要了解的区别 |
| --- | --- | --- |
| 笔记、文章、知识库 | StarterKit 与通用文档模型 | 标题、段落和列表按内容顺序排列 |
| 类似 Classic 的 Word 工作区 | Word 扩展预设与 Word 文档模型 | 还要保存分节、页眉页脚、段落样式和编号等信息 |

Word 的“标题”可以是应用了标题样式的段落，不一定叫 `heading`；一份 Word 文档也不只是普通段落外面套一个页面边框。仅更换 Canvas 或 SVG 视图，不会获得这些内容规则。

Word 预设提供相互配合的扩展和初始文档。完整示例的 `assembly/word.ts` 使用 `createClassicWordPreset()` 取得扩展，再用 `createClassicWordDefaultDocument()` 创建匹配的内容；这一步不会安装 Classic 的工具栏。该预设已经处理与 StarterKit 重叠的节点，不要再追加整套 StarterKit。

## 模型与排版怎样配合

文档模型说明“内容是什么”，文档排版配置（document profile）说明这些内容采用什么页面、段落和表格规则，View 根据排版结果显示内容并接收输入。

普通文章可以连续排版；Word 模型则由 Word 扩展提供分节和分页等规则。先复用预设即可。只有开发新的文档模型或布局能力时，才需要继续阅读 [profile 与布局注册 API](/api/extensions)。

## 读取和保存内容

```ts [读取编辑器内容]
const document = editor.state.doc
const selection = editor.state.pm.selection
const backup = editor.getJSON()
```

`state.doc` 用于读取当前结构，`state.pm.selection` 是当前选区；`getJSON()` 把正文转换成适合存储的对象，通常在保存时调用。不要另建一份响应式正文，并在每次输入时双向替换它。

保存时还应记录自己的模型版本。完整示例用 `generic-v1` 和 `word-v1` 区分两种模型，恢复前检查版本和 Schema。后面切换 Canvas/SVG 只改变显示方式，保存的数据仍属于原来的模型。

下一章：[让文档显示为 Canvas/SVG](/build/view)。两种模型的完整装配文件都可以在[工程参考](/build/reference)中查阅。
