🧠 打造一个智能交互式文本对比编辑器 —— 基于 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 编辑器高亮差异内容
- 每段差异右侧有「合并」「拒绝」按钮
- 选中文字后浮出按钮可输入自定义问题
最后ps:小弟写不来文章全靠ai帮我写的🤔