问题产生
刚学习的netty,就想尝试着共享文档怎么做,于是在写的过程中发现需要一个 diff 操作,即比较两份新旧json数据的不一致,然后与共享的小伙伴进行文档同步,于是就简单的写了个demo
import { JsonArray, JsonObject } from "type-fest";
/*
* @Description:
* @Date: 2022-10-06 14:56:52
* @LastEditTime: 2022-10-06 15:56:42
* @FilePath: \scm-vue\src\hooks\json-diff\index.ts
*/
interface optData {
// 操作的方法
opt: string;
// 全路径
fullPath: string;
attributeName: string;
context: any;
deep: number;
}
/**
* 获取数据类型
* @param {*} obj
*/
function getTypeByObj(obj: Object) {
return Object.prototype.toString
.call(obj)
.match(/^\[object ([a-zA-Z]*)\]$/)[1];
}
/**
* 判断是否是空对象
* @param {*} obj
*/
function isEmptyObject(obj: any) {
for (var key in obj) {
return false;
}
return true;
}
function findAddandChangediff(
newJson: JsonObject | JsonArray,
oldJson: JsonObject | JsonArray,
deep: number,
fullPath: string
) {
// 判断两个json不为空
if (
!newJson ||
isEmptyObject(newJson) ||
!oldJson ||
isEmptyObject(oldJson)
) {
return null;
}
let opt = new Array<optData>();
for (let attributeName in newJson) {
// 判断 是否是新增 如果在老文档中不存在就是新增
if (!oldJson[attributeName]) {
opt.push({
opt: "add",
fullPath: fullPath,
attributeName: attributeName,
context: newJson[attributeName],
deep: deep,
});
}
// 判断数据类型是否一致
else if (
getTypeByObj(oldJson[attributeName]) ===
getTypeByObj(newJson[attributeName])
) {
//由于 json 可以嵌套结构 因此需要递归
if (
getTypeByObj(oldJson[attributeName]) === "Array" ||
getTypeByObj(oldJson[attributeName]) === "Object"
) {
// 递归
const diffData = findAddandChangediff(
newJson[attributeName],
oldJson[attributeName],
deep + 1,
fullPath + "/" + attributeName
);
if (!isEmptyObject(diffData)) {
opt.push(...diffData);
}
// 如果内容不一致就是修改了
} else if (newJson[attributeName] !== oldJson[attributeName]) {
opt.push({
opt: "change",
fullPath: fullPath,
attributeName: attributeName,
context: newJson[attributeName],
deep: deep,
});
}
// 数据类型不一致也是修改了
} else {
opt.push({
opt: "change",
fullPath: fullPath,
attributeName: attributeName,
context: newJson[attributeName],
deep: deep,
});
}
}
return opt;
}
// 找到删除的节点 只需要将上面的代码的 入参 改变一下就可以得到 删除的节点了
function findRemoveDiff(
newJson: JsonObject | JsonArray,
oldJson: JsonObject | JsonArray
) {
const data = findAddandChangediff(oldJson, newJson, 0, "").filter(
(item) => item.opt === "add"
);
data.forEach(function (item) {
item.opt = "delete";
});
return data;
}
// 外面调用此方法就可以得到增加 修改 删除的节点分别是什么了
function diff(
newJson: JsonObject | JsonArray,
oldJson: JsonObject | JsonArray,
deep: number,
fullPath: string
) {
return [
...findAddandChangediff(newJson, oldJson, deep, fullPath),
...findRemoveDiff(newJson, oldJson),
];
}
export { diff };
测试方法
let newJson = [
{
name: "aichen",
title: "title",
lv2: {
tip: "lv2-tip",
lv31: {
msg: "lv3-msg1",
},
},
add: "新增",
},
];
let oldJson = [
{
name: "aichen1",
age: 18,
title: "title",
lv2: {
tip: "lv2-tip",
lv3: {
msg: "lv3-msg",
},
},
},
];
const res = diff(newJson, oldJson, 0, "");
console.log(res);