在HTML编辑器的开发场景中,代码版本对比是高频需求,无论是多人协作时的代码合并,还是个人开发时的版本回溯,都需要快速查看不同版本间的代码差异。实现这个功能的核心是先获取两个版本的代码内容,再通过差异计算逻辑找出不同之处,最后将对比结果可视化展示在编辑器内。

核心实现思路
整个版本对比功能可以分为三个核心步骤:
- 版本内容获取:从编辑器的历史版本存储中拉取需要对比的两个版本的完整代码
- 差异计算:使用diff算法逐行比对两份代码,标记出新增、删除、修改的内容
- 结果渲染:将计算得到的差异信息按照编辑器的展示规则渲染,通常用不同颜色区分不同类型的修改
差异计算实现
我们可以使用成熟的diff算法库来计算代码差异,也可以自己实现基础的行级对比逻辑。以下是基于JavaScript实现的简单行级差异计算示例:
// 计算两个代码版本的行级差异
function calcCodeDiff(oldCode, newCode) {
// 按行拆分代码
const oldLines = oldCode.split('\n');
const newLines = newCode.split('\n');
const diffResult = [];
let oldIndex = 0;
let newIndex = 0;
// 简单逐行比对逻辑
while (oldIndex < oldLines.length || newIndex < newLines.length) {
if (oldIndex >= oldLines.length) {
// 旧版本已遍历完,剩余都是新增内容
diffResult.push({
type: 'add',
lineNum: newIndex + 1,
content: newLines[newIndex]
});
newIndex++;
} else if (newIndex >= newLines.length) {
// 新版本已遍历完,剩余都是删除内容
diffResult.push({
type: 'delete',
lineNum: oldIndex + 1,
content: oldLines[oldIndex]
});
oldIndex++;
} else if (oldLines[oldIndex] === newLines[newIndex]) {
// 行内容相同,无修改
diffResult.push({
type: 'same',
lineNum: newIndex + 1,
content: newLines[newIndex]
});
oldIndex++;
newIndex++;
} else {
// 行内容不同,标记为修改
diffResult.push({
type: 'modify',
oldLineNum: oldIndex + 1,
newLineNum: newIndex + 1,
oldContent: oldLines[oldIndex],
newContent: newLines[newIndex]
});
oldIndex++;
newIndex++;
}
}
return diffResult;
}对比结果渲染
得到差异结果后,需要将其渲染到HTML编辑器的对比视图中,通常用不同背景色区分不同类型的修改:
<style>
.diff-line {
padding: 2px 8px;
font-family: monospace;
white-space: pre;
}
.diff-add {
background-color: #e6ffed;
color: #22863a;
}
.diff-delete {
background-color: #ffeef0;
color: #b31d28;
}
.diff-modify-old {
background-color: #ffeef0;
color: #b31d28;
text-decoration: line-through;
}
.diff-modify-new {
background-color: #e6ffed;
color: #22863a;
}
.line-num {
display: inline-block;
width: 40px;
text-align: right;
margin-right: 10px;
color: #999;
}
</style>
<div id="diffContainer"></div>
<script>
// 渲染差异结果到容器
function renderDiffResult(diffResult, containerId) {
const container = document.getElementById(containerId);
container.innerHTML = '';
diffResult.forEach(item => {
const lineEl = document.createElement('div');
lineEl.className = 'diff-line';
if (item.type === 'same') {
lineEl.innerHTML = `<span class="line-num">${item.lineNum}</span>${item.content}`;
} else if (item.type === 'add') {
lineEl.className += ' diff-add';
lineEl.innerHTML = `<span class="line-num">${item.lineNum}</span>+ ${item.content}`;
} else if (item.type === 'delete') {
lineEl.className += ' diff-delete';
lineEl.innerHTML = `<span class="line-num">${item.lineNum}</span>- ${item.content}`;
} else if (item.type === 'modify') {
// 先渲染旧版本的修改行
const oldLineEl = document.createElement('div');
oldLineEl.className = 'diff-line diff-modify-old';
oldLineEl.innerHTML = `<span class="line-num">${item.oldLineNum}</span>- ${item.oldContent}`;
container.appendChild(oldLineEl);
// 再渲染新版本的修改行
lineEl.className += ' diff-modify-new';
lineEl.innerHTML = `<span class="line-num">${item.newLineNum}</span>+ ${item.newContent}`;
}
container.appendChild(lineEl);
});
}
</script>编辑器适配注意事项
如果是在已有的HTML编辑器(比如富文本编辑器、代码编辑器)中集成版本对比功能,还需要注意以下几点:
- 如果编辑器有语法高亮功能,需要在渲染差异行时保留高亮逻辑,避免对比视图失去代码可读性
- 对于大文件对比,建议增加分页或者虚拟滚动逻辑,避免一次性渲染过多内容导致页面卡顿
- 可以支持点击差异行快速跳转到编辑器对应位置,方便用户直接修改代码
- 如果需要支持字符级差异对比,可以替换行级diff为更细粒度的字符级diff算法,不过计算成本会更高
简易调用示例
以下是完整的调用示例,模拟两个版本的代码并展示对比结果:
// 模拟两个版本的代码
const oldVersionCode = `<div class="container">
<h1>旧版本标题</h1>
<p>旧版本内容</p>
</div>`;
const newVersionCode = `<div class="container">
<h1>新版本标题</h1>
<p>新版本内容,新增了描述信息</p>
<button>新增按钮</button>
</div>`;
// 计算差异
const diffResult = calcCodeDiff(oldVersionCode, newVersionCode);
// 渲染差异结果
renderDiffResult(diffResult, 'diffContainer');通过以上步骤,就可以在HTML编辑器中实现基础的代码版本对比功能,开发者可以根据实际需求扩展差异计算逻辑和渲染样式,适配更复杂的业务场景。