---
title: "高级用法"
description: "了解 Tiptap 变更追踪中的建议分组、删除合并、协作兼容性和评论集成。"
canonical_url: "https://tiptap.zhcndoc.com/tracked-changes/usage/advanced-usage"
---

# 高级用法

了解 Tiptap 变更追踪中的建议分组、删除合并、协作兼容性和评论集成。

Tracked Changes 扩展的高级行为和集成模式。

## 建议分组

当用户连续输入或连续删除多个字符时，这些编辑会被分组成一个单一的建议，而不是针对每个字符创建一个建议。分组发生在：

1. 新编辑与现有建议**相邻**（紧挨其前或其后）
2. 现有建议由**同一用户**创建
3. 现有建议是**相同类型**（都是插入或都是删除）

满足这三个条件的连续编辑会合并为一个单一建议。

## 删除合并

当用户删除的内容与现有的删除建议重叠或相邻时，这些标记会自动合并，防止嵌套或重叠的删除。合并后的建议会使用范围内**最早创建的**原有删除标记的元数据（ID、用户、时间戳）。

这样保证了：

- 文档永远不会包含嵌套的删除标记
- 相关删除在视觉上分组显示
- 保留最初删除操作的原作者信息

## 混合内容处理

当删除或替换包含原始文本和之前建议插入内容混合的文本时：

- **建议插入**（带有 `add` 标记的文本）会立即从文档中移除
- **原始内容**（不带 `add` 标记的文本）会被标记为 `delete` 建议

这种行为符合用户预期：删除仅为建议的文本（尚未被接受的）时，文本直接消失。原始文档内容的删除需要明确的接受操作。

## 嵌套和堆叠建议

当一个用户在另一个用户尚未处理的建议内部进行编辑时，这个编辑会变成一个独立的建议，叠加在原始建议之上，并归属于编辑该内容的用户——而不是修改或丢弃原始建议。这样，多个审阅者就可以在同一文本范围上提出修改，而不会互相覆盖。

嵌套适用于行内插入、删除和替换。同一作者的编辑不会改变：如果**同一个**用户继续在自己的建议内部输入内容，它仍然会合并为一个单一建议（参见 [建议分组](#suggestion-grouping)）。嵌套只会发生在**不同**作者之间。

当建议被堆叠时，外层建议的 `text` 和 `fullText` 字段会出现差异：`text` 是作者单独贡献的文本，而 `fullText` 则包含叠加在其上方的嵌套建议插入的文本。详情和示例请参见 [`text` 与 `fullText`](https://tiptap.zhcndoc.com/tracked-changes/api-reference/types.md#text-vs-fulltext)。

### 接受和拒绝规则

| 操作           | 结果                                         |
| ------------ | ------------------------------------------ |
| 接受一个**内层**建议 | 内层建议被应用；**外层**建议保持不变。                      |
| 拒绝一个**内层**建议 | 内层建议被丢弃；**外层**建议保持不变。                      |
| 接受一个**外层**建议 | 外层建议被应用；其中的**嵌套建议会保留**，并继续作为各自独立的待处理建议存在。  |
| 拒绝一个**外层**建议 | 外层建议会被丢弃，**其中的嵌套编辑也会一并丢弃**，因为它们所依附的内容被移除了。 |

> **仅支持行内:**
>
> 仅支持行内建议的嵌套。块级嵌套建议（例如跨整块的嵌套建议）不在支持范围内。

## 标记追踪

Tracked Changes 还可以将现有文本上的标记级编辑追踪为 `markChange` 建议。这包括简单的格式标记，如 `bold` 和 `italic`，以及带有属性的标记，如 `link` 或 `highlight`。

标记追踪的行为如下：

- 在现有文本上添加或移除标记会创建 `markChange` 建议
- 应用于新插入内容的格式保留为插入建议的一部分，而不是创建第二个标记建议
- 标记变更建议存储更改的标记名称和属性，以便在接受和拒绝期间正确恢复或移除带属性的标记

### 标记追踪的工作原理

在现有文本上，追踪的标记变更记录实际提出的标记变更：

- 添加标记会创建带有 `added` 操作的 `markChange` 建议
- 移除标记会创建带有 `removed` 操作的 `markChange` 建议

例如，如果用户对单词应用 `bold`，建议会存储 `bold` 已被添加。如果用户从已格式化的文本中移除 `bold`，建议会存储 `bold` 已被移除。

带属性的标记工作方式相同，但属性是追踪变更的一部分。这对于 `link` 等标记很重要，因为确切的属性标识了正在更改的标记变体：

```js
// 建议添加特定链接
editor.commands.addTrackedMark({
  from: 7,
  to: 12,
  markName: 'link',
  markAttrs: {
    href: 'https://tiptap.dev',
    target: '_blank',
  },
})
```

在这种情况下，建议存储标记名称（`link`）和标记属性。接受或拒绝建议后可以保留、恢复或移除确切的链接标记，而不是将所有链接视为等同。

如果用户应用了一个标记，然后在同一文本上撤销了相同的标记更改，追踪的标记更改可以相互抵消，而不是留下冗余的建议。这有助于在审查期间保持嵌套和重叠的标记建议稳定。

默认情况下，Tracked Changes 忽略 `suggestion` 标记本身和内联评论/线程标记，因此这些内部标记不会创建递归的追踪建议。你也可以选择退出追踪额外的标记：

```js
TrackedChanges.configure({
  ignoredTrackingMarks: ['highlight'],
})
```

当你的应用程序具有装饰性或特定于集成的标记且绝不应出现在追踪变更中时，使用此选项。

## 表格支持

该扩展会追踪表格内的结构性变更，包括行、单元格和列操作。

**单元格选择删除** — 当用户通过 `CellSelection` 删除单元格时（即选中多个单元格后按删除键），每个被选中的单元格都会提升为节点级删除建议，而不是立即被移除。所选中的所有单元格共享相同的 `suggestionId`，因此它们会在建议列表中显示为一个分组变更。

**列删除** — 删除某一列时，会生成一个覆盖该列所有单元格的单个分组建议，而不是每个单元格各生成一个建议。

**接受和拒绝** — 接受或拒绝表格建议时，会正确处理底层的表格节点结构，防止在操作涉及列节点时出错。

要启用表格追踪，请将表格扩展与 Tracked Changes 一起引入：

```js
import { Table } from '@tiptap/extension-table'
import { TableRow } from '@tiptap/extension-table-row'
import { TableCell } from '@tiptap/extension-table-cell'
import { TableHeader } from '@tiptap/extension-table-header'
import { TrackedChanges } from '@tiptap-pro/extension-tracked-changes'

const editor = new Editor({
  extensions: [
    Table.configure({ resizable: true }),
    TableRow,
    TableCell,
    TableHeader,
    TrackedChanges.configure({ enabled: true, userId: 'user-123' }),
  ],
})
```

无需额外配置——一旦两个扩展都处于激活状态，表格变更就会自动被追踪。

## 原子节点追踪

扩展会自动追踪对原子节点（如图片、水平线和其他非文本内容）的更改。这些节点不能拥有标记，因此扩展使用节点属性（`suggestionId`、`suggestionType`、`suggestionUserId`、`suggestionCreatedAt`、`suggestionUserMetadata`）代替。这一过程是透明的——原子节点会在相同的建议查询中出现，并且可以像其他建议一样被接受或拒绝。

## 协作兼容性

该扩展设计兼容基于 Yjs 的协作。它会自动忽略：

- 来自 Yjs 的**远程同步事务**（带有 `y-sync$` 元数据）
- **历史事务**（撤销/重做由 ProseMirror 本地处理）
- **带 `addToHistory: false` 的事务**（通常为远程变更）

意味着仅跟踪本地用户的编辑作为建议。

## 评论集成

Tracked Changes 扩展与 [评论](https://tiptap.zhcndoc.com/editor/extensions/functionality/comments.md) 扩展集成，支持将建议和评论线程一起处理的复审流程。该集成基于两个扩展提供的事件系统构建。

当两个扩展同时激活时，评论线程会自动通过线程元数据与建议关联，实现双向同步：

- **解决**与建议关联的评论线程会自动**接受**该建议
- **删除**与建议关联的评论线程会自动**拒绝**该建议
- **接受**建议会自动**解决**其关联的评论线程
- **拒绝**建议会自动**删除**其关联的评论线程

当建议内容发生变化（例如用户在跟踪插入中继续输入）时，关联线程的元数据会更新以保持同步。

这意味着用户可以通过建议 UI 或评论面板审阅变更，两者保持一致。

## 代码块兼容性

默认情况下，Tiptap 代码块不允许使用标记，这阻碍了建议标记在代码内容内部的应用。该扩展导出辅助函数来解决此问题：

```js
import { CodeBlock } from '@tiptap/extension-code-block'
import { TrackedChanges, withSuggestionMarkOnCodeBlock } from '@tiptap-pro/extension-tracked-changes'
import StarterKit from '@tiptap/starter-kit'

const TrackableCodeBlock = withSuggestionMarkOnCodeBlock(CodeBlock)

const editor = new Editor({
  extensions: [
    StarterKit.configure({
      codeBlock: false, // 禁用默认代码块
    }),
    TrackableCodeBlock, // 使用修补后的版本
    TrackedChanges.configure({ enabled: true, userId: 'user-123' }),
  ],
})
```

这同样适用于 `CodeBlockLowlight` 或其他代码块扩展。
