🧠 打造一个智能交互式文本对比编辑器 —— 基于 Monaco Editor 的完整实现

799 阅读3分钟

🧠 打造一个智能交互式文本对比编辑器 —— 基于 Monaco Editor 的完整实现

📌 项目简介

在代码评审、内容协同编辑、版本对比等场景中,“查看差异、快速合并、更智能地对内容进行提问或修改” 是一个常见的需求。

本项目基于 Monaco Editor 打造了一个高度交互的编辑器,具备以下能力:

  • ✅ 支持左右文本差异比对(diff)
  • 🎨 高亮新增 / 删除行
  • 🔀 差异段落可一键合并或拒绝
  • 🧠 对任意选中内容进行提问(弹出输入框)
  • 🔄 支持撤销/重做差异合并操作
  • 💡 美观、响应式、可交互性强

🧩 技术栈

技术用途
monaco-editor核心编辑器能力
monaco.ViewZone自定义悬浮区域插入
model.deltaDecorations实现行高亮样式
HTML + CSS完善界面交互和视觉美化
JavaScript控制交互逻辑和差异处理流程

🧱 核心功能拆解

1️⃣ Monaco 编辑器初始化

  • 使用 createEditor 创建编辑器实例
  • 监听 onDidChangeModelContent 捕捉内容变更
  • 使用 createViewZone 为选中内容添加悬浮按钮区域
editorRef.current = monaco.editor.create(...);
editorRef.current.onDidChangeModelContent(() => {
  const text = editorRef.current.getValue();
  // 更新数据状态
});

2️⃣ 文本差异分析与分组(Diff Grouping)

通过自定义 groupDiffs() 函数,将对比内容分为:

  • unchanged:未变更行
  • change:修改行(添加 + 删除)
  • added:新增内容
  • removed:删除内容
function groupDiffs() {
  const groups = [];
  for (let i = 0; i < rawDiff.length; i++) {
    const current = rawDiff[i];
    const next = rawDiff[i + 1];
    if (current.added && next?.removed) {
      groups.push({ type: 'change', added: current.value, removed: next.value });
      i++;
    } else if (current.removed) {
      groups.push({ type: 'removed', value: current.value });
    } else if (current.added) {
      groups.push({ type: 'added', value: current.value });
    } else {
      groups.push({ type: 'unchanged', value: current.value });
    }
  }
  return groups;
}

3️⃣ 差异区域渲染与样式高亮

  • 使用 editor.deltaDecorations() 对差异段落进行蓝色 / 红色渐变高亮。
  • 同时创建合并按钮悬浮区域。
decorationsRef.current = editorRef.current.deltaDecorations([], decorations);

4️⃣ 差异处理:合并 / 拒绝 + 撤销操作

为每个差异段创建按钮:

  • Accept 按钮:将改动写入 original
  • Reject 按钮:保留原始内容
  • 🔁 所有操作 push 到 historyRef 中以支持撤销
historyRef.current.push({
  type: 'merge',
  original,
  updated,
});

5️⃣ 智能提问:选中内容 → 弹出输入框

  • 监听 onDidChangeCursorSelection
  • 动态创建 ViewZone 区域
  • 在该区域中注入提问按钮与输入框,支持确认 / 取消行为

🎨 样式美化(CSS 特性)

样式文件非常丰富,仅列出部分关键亮点:

  • 差异行样式(蓝色渐变新增、红色渐变删除)
  • 合并按钮(绿色渐变)、拒绝按钮(红色渐变)
  • 选中内容按钮为圆形渐变、带光泽动效
  • 提问输入框支持玻璃拟态、聚焦高亮
  • 所有交互组件均具备 hover / active 动效
/* 差异新增高亮 */
.diff-line-added {
  background: linear-gradient(90deg,
      rgba(100, 237, 255, 0.25) 0%,
      rgba(100, 237, 255, 0.15) 50%,
      rgba(100, 237, 255, 0.1) 100%) !important;
  border-left: 2px solid rgba(100, 237, 255, 1) !important;
}

/* 删除行样式 */
.remove-line {
  background: linear-gradient(90deg,
      rgba(255, 107, 107, 0.2) 0%,
      rgba(255, 107, 107, 0.1) 50%,
      rgba(255, 107, 107, 0.05) 100%) !important;
  border-left: 2px solid #ff6b6b !important;
  color: #d32f2f !important;
}

🖼 效果预览

以下为页面示意:

  • Monaco 编辑器高亮差异内容
  • 每段差异右侧有「合并」「拒绝」按钮
  • 选中文字后浮出按钮可输入自定义问题

image.png

image.png

image.png

最后ps:小弟写不来文章全靠ai帮我写的🤔