WEB开发时,页面上的数据输入通常有下面几种类型,从简单到复杂依次有
表单数据输入:一维结构
表格数据输入:二维结构
树状数据输入:三维以上的结构
表单数据最简单,表格数据比较麻烦,树状数据比较复杂。
提交方式有2种,单个提交和统一提交,树状数据统一提交则是最复杂的一种,因为你必须记录用户增删改的数据,这些数据有层级关系和时间关系。
比如说下面的树状数据
父1
L子1
L孙1
L子2
父2
L子3
画面操作:
1.在子1下面添加孙2
2.在子2下面添加孙3
3.删除子2
变换成后台数据库的操作只有下面2步,因为孙3在子2下面,子2删除后孙3的添加就无效了。
1.在子1下面添加孙2
2.删除子2
记录用户增删改的数据,分析其中的层级关系和时间关系,才能得到正确的修改数据库指令。
这个非常麻烦,换个思路,我们只需要把修改前后的数据做成json进行对比,就能得到正确的修改数据库指令。
每条数据需要一个ID来标记,新增的ID可以使用UUID或者自己设置一个不重复的番号。在对比中就能发现哪些数据有增删改,最后形成修改数据库指令。
这样做的好处就是不用在输入的过程中记录各种标记和状态,这个非常容易出错,对比json的差异简单可靠性高。
下面是我的实现代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
test
</body>
<script>
var source1=[
{
"CLIENT_CD": "pm",
"COMMENT": [
{
"ID":"pm36",
"CONFIRM_ITEM": "注释",
"FILE": [
{
"FILE_ID":"pm36_1599614744",
"FILE_SRC": "deleted file pm36_1599614744"
},
]
},
{
"ID":"pm361",
"CONFIRM_ITEM": "注释",
"FILE": [
{
"FILE_ID":"pm361_1599614744",
"FILE_SRC": "file pm36_15996147441"
},
]
}
]
},
{
"CLIENT_CD": "mbt",
"COMMENT": [
{
"ID":"mbt136",
"CONFIRM_ITEM": "注释",
"FILE": [
{
"FILE_ID":"mbt136_1599614744",
"FILE_SRC": "deleted file mbt136_1599614744"
},
]
}
]
},
{
"CLIENT_CD": "obk",
}
];
var source2=[
{
"CLIENT_CD": "pm",
"COMMENT": [
{
"ID":"pm36",
"CONFIRM_ITEM": "!注释",
"FILE": [
{
"FILE_ID":"new_pm36_x1599614744",
"FILE_SRC": "inserted file new_pm36_x1599614744"
},
]
},
{
"ID":"pm361",
"CONFIRM_ITEM": "注释",
"FILE": [
{
"FILE_ID":"pm361_1599614744",
"FILE_SRC": "file pm36_15996147441"
},
]
}
]
},
{
"CLIENT_CD": "mbt",
"COMMENT": [
{
"ID":"mbt136",
"CONFIRM_ITEM": "注释",
"FILE": [
{
"FILE_ID":"new_mbt136_ZZ1599614744",
"FILE_SRC": "inserted file new_mbt136_ZZ1599614744"
},
]
},
{
"ID":"mbt236",
"CONFIRM_ITEM": "追加注释",
"FILE": [
{
"FILE_ID":"new_mbt236_1599614744",
"FILE_SRC": "追加文件"
},
]
}
]
},
{
"CLIENT_CD": "obk",
}
];
//获取文件的变更
function getFileChanged(list1,list2,result){
//获取删除的文件
for (var i in list1.FILE) {
var file=findObjectById(list2.FILE,"FILE_ID",list1.FILE[i].FILE_ID);
if(file==undefined){
var obj={};
obj.MODE="file_delete";
obj.FILE_ID=list1.FILE[i].FILE_ID;
result.push(obj);
}
}
//获取追加的文件
for (var i in list2.FILE) {
var file=findObjectById(list1.FILE,"FILE_ID",list2.FILE[i].FILE_ID);
if(file==undefined){
var obj={};
obj.MODE="file_insert";
obj.ID=list2.ID;
obj.FILE_SRC=list2.FILE[i].FILE_SRC;
result.push(obj);
}
}
}
function findObjectById(list,id,value){
if(list.find)
return list.find(obj=>obj[id]==value);
//ie 不支持find方法,用循环查找
for (var i in list) {
if(list[i][id]==value) return list[i];
}
return undefined;
}
//获取注释的变更
function getCommentChanged(clientCd,list1,list2,result){
//获取修改或者删除的注释
for (var i in list1) {
var comment=findObjectById(list2,"ID",list1[i].ID);
if(comment!=undefined){
if(list1[i].CONFIRM_ITEM!=comment.CONFIRM_ITEM){
var obj={};
obj.MODE="update";
obj.ID=list1[i].ID;
obj.CONFIRM_ITEM=comment.CONFIRM_ITEM;
result.push(obj);
}
getFileChanged(list1[i],comment,result);
}else{
var obj={};
obj.MODE="delete";
obj.ID=list1[i].ID;
result.push(obj);
}
}
//获取追加的注释
for (var i in list2) {
var comment=findObjectById(list1,"ID",list2[i].ID);
if(comment==undefined){
var obj={};
obj.MODE="insert";
obj.CLIENT_CD=clientCd;
obj.CONFIRM_ITEM=list2[i].CONFIRM_ITEM;
result.push(obj);
var files={}
for (var j in list2[i].FILE) {
var obj={};
obj.MODE="file_insert";
obj.FILE_SRC=list2[i].FILE[j].FILE_SRC;
result.push(obj);
}
}
}
}
function getChanged(source1,source2){
var result=[];
for (var i in source1) {
getCommentChanged(source1[i].CLIENT_CD,source1[i].COMMENT,source2[i].COMMENT,result);
}
return result;
}
var result=getChanged(source1,source2);
console.debug(JSON.stringify(result, null, " "));
alert("ok");
</script>
</html>
下面是输出结果数组,MODE是数据的操作指令,发送到后台后遍历这个数组就能形成SQL来修改数据库。对于二维表格也可以用同样的思路来实现,而且更简单。
json_diff2.html:206 [
{
"MODE": "update",
"ID": "pm36",
"CONFIRM_ITEM": "!注释"
},
{
"MODE": "file_delete",
"FILE_ID": "pm36_1599614744"
},
{
"MODE": "file_insert",
"ID": "pm36",
"FILE_SRC": "inserted file new_pm36_x1599614744"
},
{
"MODE": "file_delete",
"FILE_ID": "mbt136_1599614744"
},
{
"MODE": "file_insert",
"ID": "mbt136",
"FILE_SRC": "inserted file new_mbt136_ZZ1599614744"
},
{
"MODE": "insert",
"CLIENT_CD": "mbt",
"CONFIRM_ITEM": "追加注释"
},
{
"MODE": "file_insert",
"FILE_SRC": "追加文件"
}
]