在Angular中实现deepDiff JSON对比结果高亮的问题求助
解决deepDiff JSON差异高亮失效问题
原代码核心问题分析
- 正则匹配错误:使用HTML转义符
"替代原生双引号,导致无法匹配JSON字符串中的键名;未转义值中的正则特殊字符(如{、[、.),引发匹配异常。 - 差异类型逻辑混乱:
- 修改类型(
E)未区分文件:file1应高亮旧值diff.lhs,file2应高亮新值diff.rhs,原代码统一用diff.rhs导致file1匹配失败。 - 新增(
N)、删除(D)类型未过滤无效文件:新增项仅存在于file2,删除项仅存在于file1,原代码未做区分,产生无效匹配。
- 修改类型(
- 数组差异未处理:完全忽略
A类型的数组差异,无法高亮数组内的变动项。 - 匹配精度不足:仅通过最后一个路径段+值匹配,遇到同名键且值相同时,会错误匹配无关节点。
修正后的实现代码
1. 更新差异对比函数(传递文件标识)
compareFiles() { if (this.file1Content && this.file2Content) { const differences = deepDiff.diff(this.file1Content.apis, this.file2Content.apis); if (differences) { this.comparisonResult = this.formatDifferences(differences); const filteredDifferences = differences.filter(diff => diff.path && !diff.path.some(p => p.key === 'index' && p.ignoreOrder)); this.comparisonResult2 = filteredDifferences ? JSON.stringify(filteredDifferences, null, 2) : 'No differences found.'; // 传递文件类型标识,让高亮函数知道处理的是哪份文件 this.highlightedFile1Content = this.getHighlights(this.file1Content, differences, 'file1'); this.highlightedFile2Content = this.getHighlights(this.file2Content, differences, 'file2'); } } }
2. 修正高亮生成函数(含辅助工具函数)
// 辅助函数:转义正则特殊字符,避免匹配异常 escapeRegExp(str: string): string { return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } getHighlights(jsonObject: any, differences: deepDiff.Diff<any, any>[], fileType: 'file1' | 'file2'): string { try { let jsonString = JSON.stringify(jsonObject, null, 2); const lines = jsonString.split('\n'); differences.forEach(diff => { if (!diff.path || diff.path.length === 0) return; let targetValue: any; let shouldProcess = true; // 根据文件类型和差异类型,确定要高亮的目标值 switch (diff.kind) { case 'E': targetValue = fileType === 'file1' ? diff.lhs : diff.rhs; break; case 'N': shouldProcess = fileType === 'file2'; // 新增项仅在file2中存在 targetValue = diff.rhs; break; case 'D': shouldProcess = fileType === 'file1'; // 删除项仅在file1中存在 targetValue = diff.lhs; break; case 'A': // 处理数组内部的子差异 if (diff.item) { if (fileType === 'file1') { targetValue = (diff.item.kind === 'D' || diff.item.kind === 'E') ? diff.item.lhs : undefined; } else { targetValue = (diff.item.kind === 'N' || diff.item.kind === 'E') ? diff.item.rhs : undefined; } } break; default: shouldProcess = false; } if (!shouldProcess || targetValue === undefined) return; const targetValueStr = JSON.stringify(targetValue); const escapedValue = this.escapeRegExp(targetValueStr); const lastSegment = diff.path[diff.path.length - 1]; // 构建键名的正则匹配串(区分数组索引和对象键) const keyStr = typeof lastSegment === 'number' ? `\\[${lastSegment}\\]` : `"${lastSegment}"`; // 根据路径层级计算缩进,确保只匹配对应层级的节点 const indentLevel = diff.path.length - 1; const indent = ' '.repeat(indentLevel); const regex = new RegExp(`^${this.escapeRegExp(indent)}${keyStr}:\\s*${escapedValue}`); // 遍历行查找匹配,找到后立即退出避免重复替换 for (let i = 0; i < lines.length; i++) { if (lines[i].match(regex)) { lines[i] = lines[i].replace(escapedValue, `<span class="highlight">${targetValueStr} DIFFERENCE FOUND!</span>`); break; } } }); return lines.join('\n'); } catch (e) { console.error("Error in getHighlights:", e); return JSON.stringify(jsonObject, null, 2); } }
关键优化点说明
- 文件类型区分:通过
fileType参数精准控制不同文件应高亮的差异值,避免无效匹配。 - 正则安全处理:用
escapeRegExp转义特殊字符,防止正则语法错误。 - 层级缩进匹配:根据路径层级计算缩进,确保只匹配对应层级的键值对,解决同名键误匹配问题。
- 数组差异支持:处理
A类型的数组内部差异,覆盖数组元素的新增、删除、修改场景。 - 精准匹配退出:找到目标行后立即break,避免相同值的其他节点被错误替换。
内容的提问来源于stack exchange,提问作者m s
相关产品推荐
相关产品推荐

