Skip to content

快照对比

本页演示 power-editor 的快照对比流程。

  1. 准备两份 Tiptap JSON 文档。
  2. 分别用 power-editor 渲染源文档和目标文档。
  3. 通过 getJSON() 读取两边编辑器内容。
  4. 使用 computeDiff()diffTool.compareDiff() 计算差异。
  5. 将最终审阅结果渲染到另一个 power-editor 中。

说明

快照对比用于把两个编辑器快照转换为可审阅的差异结果,适合版本预览、草稿校对、审批确认和变更回放。

主编辑器中的 Diff Props

下面这些属性已经在主编辑器 power-editor 上可直接使用,既可以用于本页示例,也可以用于你自己的审阅页面。

属性类型默认值说明
diffInlineBlockTypesstring[][]扩展按“行内内容 diff”处理的块级节点类型。适合外观像块节点、但内容仍应逐段比较的自定义节点。
diffContainerBlockTypesstring[][]扩展按“容器节点 diff”处理的块级节点类型。适合包装器、布局容器、多子节点结构。
diffInsertColorstring""插入变更主色。
diffDeleteColorstring""删除变更主色。
diffInsertColorSecstring""插入变更辅助色,常用于边框或装饰。
diffDeleteColorSecstring""删除变更辅助色。
diffInsertHoverColorstring""鼠标移入插入变更时的高亮色。
diffDeleteHoverColorstring""鼠标移入删除变更时的高亮色。
diffInsertHoverColorSecstring""插入变更 hover 状态的辅助色。
diffDeleteHoverColorSecstring""删除变更 hover 状态的辅助色。

推荐场景

  • 自定义段落类节点时,优先补充到 diffInlineBlockTypes
  • 自定义容器、卡片、布局块时,优先补充到 diffContainerBlockTypes
  • 如果你的审阅界面有品牌色或深浅主题切换,建议同时配置普通态和 hover 态颜色。
>
运行对比
下方最终审阅编辑器由 index.js 生成结果后渲染。

源快照

目标快照

审阅结果

示例

在当前文档仓库中

本页在线示例直接引用源码文件,因为这里的 VitePress 就运行在同一个仓库里:

js
import { computeDiff } from "@/packages/editor/src/js/diffTool/index.js";
import { applyTrackedGroup } from "@/packages/editor/src/js/diffTool/apply.js";

执行 yarn add @creatorsn/powereditor3 之后

发布到 npm 并安装后,不要再从上面的内部源码路径导入,而应该从包根入口导入:

js
import {
    computeDiff,
    diffTool,
    applyTrackedGroup,
} from "@creatorsn/powereditor3";

如果你只使用默认的对比流程,那么 computeDiff(sourceDoc, targetDoc) 就够用了。

如果你希望使用可配置写法,也可以这样写:

js
import { diffTool } from "@creatorsn/powereditor3";

const result = diffTool
    .configure({
        extendInlineDiffBlockTypes: ["customParagraphLike"],
        extendContainerDiffBlockTypes: ["customContainerLike"],
    })
    .compareDiff(sourceDoc, targetDoc);

使用 <power-editor> 暴露的方法

power-editor 组件实例同样暴露了 compareDiff()。如果你已经拿到了编辑器 ref,并且希望复用编辑器级别的配置入口,也可以直接这样调用:

vue
<script setup>
import { ref } from "vue";

const reviewEditorRef = ref(null);

function compareWithEditor(sourceDoc, targetDoc) {
    return reviewEditorRef.value?.compareDiff?.(sourceDoc, targetDoc);
}
</script>

本页主示例仍然使用直接调用 computeDiff() + applyTrackedGroup() 的方式,因为这样更便于看清整条 diff 处理链路。

vue
<script setup>
import { ref } from "vue";
import { computeDiff, applyTrackedGroup } from "@creatorsn/powereditor3";

const sourceEditorRef = ref(null);
const targetEditorRef = ref(null);
const reviewEditorRef = ref(null);
const reviewContent = ref({
    type: "doc",
    content: [],
});
const reviewChanges = ref([]);

function collectReviewChanges(reviewDoc) {
    return [];
}

function compareSnapshots() {
    const sourceJson = sourceEditorRef.value?.editor?.()?.getJSON();
    const targetJson = targetEditorRef.value?.editor?.()?.getJSON();
    const result = computeDiff(sourceJson, targetJson);

    reviewContent.value = result.reviewDoc;
    reviewChanges.value = collectReviewChanges(result.reviewDoc);
}

function applyChange(groupId, action) {
    const editor = reviewEditorRef.value?.editor?.();

    if (!editor) return;

    applyTrackedGroup(editor, groupId, action);
    reviewContent.value = editor.getJSON();
    reviewChanges.value = collectReviewChanges(reviewContent.value);
}
</script>

<template>
    <power-editor ref="sourceEditorRef" :model-value="sourceContent"></power-editor>
    <power-editor ref="targetEditorRef" :model-value="targetContent"></power-editor>
    <power-editor ref="reviewEditorRef" :model-value="reviewContent" :editable="false" :showToolBar="false"></power-editor>
    <fv-button @click="compareSnapshots">执行对比</fv-button>
    <fv-button @click="applyChange(reviewChanges[0]?.groupId, 'accept')">接受第一条变更</fv-button>
</template>

说明事项

  • 本示例中的 model-value 使用的是 Tiptap JSON 文档,而不是 HTML 字符串。
  • 段落行内内容现在支持 texthardBreakinlineEquation 等多种行内原子节点。
  • computeDiff() 会同时返回 chunksreviewDoc
  • diffTool.compareDiff() 返回的数据结构与 computeDiff() 一致。
  • reviewDoc 可以直接交给 power-editor 渲染成最终对比结果。
  • 安装包之后,可以从 @creatorsn/powereditor3 直接导入 applyTrackedGroup()

MIT Licensed