平时我们会遇到一些深层次的类目数据,以下将会介绍几种常用到的数据处理方法,一般使用递归函数来操作数据,代码清晰不冗余,而且方法复用性较好,不用考虑数据层次的深度问题。
平铺数据转为Tree数据
// value属性为唯一标识的属性, parentId为关联父节点的属性
const data = [
{ label: '1', value: '1' },
{ label: '2-1', value: '2-1', parentId: '2' },
{ label: '1-1', value: '1-1', parentId: '1' },
{ label: '3', value: '3' },
{ label: '3-1-2-1', value: '3-1-2-1', parentId: '3-1-2' },
{ label: '3-1', value: '3-1', parentId: '3' },
{ label: '3-2', value: '3-2', parentId: '3' },
{ label: '2', value: '2' },
{ label: '3-1-1', value: '3-1-1', parentId: '3-1' },
{ label: '3-1-2', value: '3-1-2', parentId: '3-1' },
{ label: '3-1-1-1', value: '3-1-1-1', parentId: '3-1-1' },
{ label: '1-1-1', value: '1-1-1', parentId: '1-1'},
];
/*
* data:array 数组内部元素为对象,需要有后续两个参数对应的属性,relativeKey属性的值可以为空
* uniqueKey: string 数组中每一项对象中唯一的标识所对应的属性
* relativeKey: string 数组中每一项对象中关联父节点所对应的属性
*/
const generateTree = (data, uniqueKey, relativeKey) => {
if (Array.isArray(data) && data.length > 0) {
const treeData = []; // 最后返回的tree结构数据
const temptree = {}; // 中间状态的数据
const hasChildData = []; // data中添加children属性后的数据
data.forEach(item => {
if (!temptree[item[uniqueKey]]) {
let temp = item;
temp.children = [];
temptree[item[uniqueKey]] = temp;
hasChildData.push(temp);
}
});
hasChildData.forEach(item => {
// 如果有父节点则插入对应的children中
if (temptree[item[relativeKey]]) {
temptree[item[relativeKey]].children.push(temptree[item[uniqueKey]])
} else {
// 无父节点则直接插入最终的数据中
treeData.push(temptree[item[uniqueKey]]);
}
});
return treeData;
} else {
return [];
}
}
console.log(JSON.stringify(
generateTree(data, 'value', 'parentId'),
null,
2
));
深层次遍历数据
const categoryData = [
{"label":'1',"value":"1","children":[
{"label":"1-1","value":"1-1","parentId":"1","children":[
{"label":"1-1-1","value":"1-1-1","parentId":"1-1","children":[]}
]}
]},
{"label":'3',"value":"3","children":[
{"label":"3-1","value":"3-1","parentId":"3","children":[
{"label":"3-1-1","value":"3-1-1","parentId":"3-1","children":[
{"label":"3-1-1-1","value":"3-1-1-1","parentId":"3-1-1","children":[]}
]},
{"label":"3-1-2","value":"3-1-2","parentId":"3-1","children":[
{"label":"3-1-2-1","value":"3-1-2-1","parentId":"3-1-2","children":[]}
]}
]},
{"label":"3-2","value":"3-2","parentId":"3","children":[]}
]},
{"label":'2',"value":"2","children":[
{"label":"2-1","value":"2-1","parentId":"2","children":[]}
]}
];
/*
* data:array 类目结构的数据,数组内部元素为对象
* changeLabelList:array[array] 所需要将原数据中的属性变成期望属性的对应关系,内部数组第一项为源数据中的属性,第二项是新数据的属性
* copyPrev:boolean 是否要保留原数据中的所有属性
*/
const mapCategoryData = (data, changeLabelList, copyPrev = true) => {
if (Array.isArray(data) && data.length > 0) {
const newData = [];
data.forEach(item => {
let obj = copyPrev ? { ...item } : {};
changeLabelList.forEach(item1 => {
obj[item1[1]] = item[item1[0]];
});
if (Array.isArray(item.children) && item.children.length > 0) {
const tempData = mapCategoryData(item.children, changeLabelList, copyPrev);
obj.children = tempData;
}
newData.push(obj);
});
return newData;
} else {
return [];
}
}
console.log(JSON.stringify(
mapCategoryData(
categoryData,
[
['label', 'name'],
['value', 'id'],
],
true
),
null,
2
));
根据所有最后一级的唯一值得到想要的类目结构数据
const categoryData = [
{"label":'1',"value":"1","children":[
{"label":"1-1","value":"1-1","parentId":"1","children":[
{"label":"1-1-1","value":"1-1-1","parentId":"1-1","children":[]}
]}
]},
{"label":'3',"value":"3","children":[
{"label":"3-1","value":"3-1","parentId":"3","children":[
{"label":"3-1-1","value":"3-1-1","parentId":"3-1","children":[
{"label":"3-1-1-1","value":"3-1-1-1","parentId":"3-1-1","children":[]}
]},
{"label":"3-1-2","value":"3-1-2","parentId":"3-1","children":[
{"label":"3-1-2-1","value":"3-1-2-1","parentId":"3-1-2","children":[]}
]}
]},
{"label":"3-2","value":"3-2","parentId":"3","children":[]}
]},
{"label":'2',"value":"2","children":[
{"label":"2-1","value":"2-1","parentId":"2","children":[]}
]}
];
/*
* data:array 类目结构的数据,数组内部元素为对象
* values:array 所选中的最后一级的values(必须是最后一级)
* uniqueKey:string 数组中每一项对象中唯一的标识所对应的属性
* type: select or filter select根据values生成选择的类目数据, filter根据values生成过滤后的类目数据
*/
const filterCategoryData = (data, values, uniqueKey, type = 'select') => {
if (Array.isArray(values) && values.length > 0) {
const newValues = Array.isArray(values) ? values : [values];
const newData = [];
data.forEach(item => {
let obj = {};
if (Array.isArray(item.children) && item.children.length > 0) {
const tempData = filterCategoryData(item.children, newValues, uniqueKey, type);
obj = {
...item,
children: tempData,
};
// 当children不为空时才保留该数据
if (obj.children.length > 0) {
newData.push(obj);
}
} else if (
type === 'select' ? newValues.includes(item[uniqueKey]) : !newValues.includes(item[uniqueKey])
) {
obj = {
...item,
};
newData.push(obj);
}
});
return newData;
} else {
return data;
}
};
console.log(JSON.stringify(
filterCategoryData(categoryData, ['1-1-1', '3-1-2-1', '3-2'], 'value', 'select'),
null,
2
));
过滤掉类目数据中指定删除的值
const categoryData = [
{"label":'1',"value":"1","children":[
{"label":"1-1","value":"1-1","parentId":"1","children":[
{"label":"1-1-1","value":"1-1-1","parentId":"1-1","children":[]}
]}
]},
{"label":'3',"value":"3","children":[
{"label":"3-1","value":"3-1","parentId":"3","children":[
{"label":"3-1-1","value":"3-1-1","parentId":"3-1","children":[
{"label":"3-1-1-1","value":"3-1-1-1","parentId":"3-1-1","children":[]}
]},
{"label":"3-1-2","value":"3-1-2","parentId":"3-1","children":[
{"label":"3-1-2-1","value":"3-1-2-1","parentId":"3-1-2","children":[]}
]}
]},
{"label":"3-2","value":"3-2","parentId":"3","children":[]}
]},
{"label":'2',"value":"2","children":[
{"label":"2-1","value":"2-1","parentId":"2","children":[]}
]}
];
/*
* data:array 类目结构的数据,数组内部元素为对象
* values:array 所要删除的values
* uniqueKey:string 数组中每一项对象中唯一的标识所对应的属性
*/
const deleteAppointData = (data, values, uniqueKey) => {
const newValues = values ? Array.isArray(values) ? values : [values] : [];
if (values.length > 0) {
const newData = [];
data.forEach(item => {
let obj = { ...item };
if (!newValues.includes(item[uniqueKey])) {
if (Array.isArray(item.children) && item.children.length > 0) {
const tempData = deleteAppointData(item.children, newValues, uniqueKey);
obj.children = tempData;
}
newData.push(obj);
}
});
return newData;
} else {
return data;
}
}
console.log(JSON.stringify(
deleteAppointData(
categoryData,
['2', '3-1-1'],
'value'
),
null,
2
));
过滤掉类目数据中指定删除的值
const categoryData = [
{"label":'1',"value":"1","children":[
{"label":"1-1","value":"1-1","parentId":"1","children":[
{"label":"1-1-1","value":"1-1-1","parentId":"1-1","children":[]}
]}
]},
{"label":'3',"value":"3","children":[
{"label":"3-1","value":"3-1","parentId":"3","children":[
{"label":"3-1-1","value":"3-1-1","parentId":"3-1","children":[
{"label":"3-1-1-1","value":"3-1-1-1","parentId":"3-1-1","children":[]}
]},
{"label":"3-1-2","value":"3-1-2","parentId":"3-1","children":[
{"label":"3-1-2-1","value":"3-1-2-1","parentId":"3-1-2","children":[]}
]}
]},
{"label":"3-2","value":"3-2","parentId":"3","children":[]}
]},
{"label":'2',"value":"2","children":[
{"label":"2-1","value":"2-1","parentId":"2","children":[]}
]}
];
/*
* data:array 类目结构的数据,数组内部元素为对象
* values:array 所要删除的values
* uniqueKey:string 数组中每一项对象中唯一的标识所对应的属性
*/
const deleteAppointData = (data, values, uniqueKey) => {
const newValues = values ? Array.isArray(values) ? values : [values] : [];
if (values.length > 0) {
const newData = [];
data.forEach(item => {
let obj = { ...item };
if (!newValues.includes(item[uniqueKey])) {
if (Array.isArray(item.children) && item.children.length > 0) {
const tempData = deleteAppointData(item.children, newValues, uniqueKey);
obj.children = tempData;
}
newData.push(obj);
}
});
return newData;
} else {
return data;
}
}
console.log(JSON.stringify(
deleteAppointData(
categoryData,
['2', '3-1-1'],
'value'
),
null,
2
));
获取截止到指定层级的数据
const categoryData = [
{"label":'1',"value":"1","children":[
{"label":"1-1","value":"1-1","parentId":"1","children":[
{"label":"1-1-1","value":"1-1-1","parentId":"1-1","children":[]}
]}
]},
{"label":'3',"value":"3","children":[
{"label":"3-1","value":"3-1","parentId":"3","children":[
{"label":"3-1-1","value":"3-1-1","parentId":"3-1","children":[
{"label":"3-1-1-1","value":"3-1-1-1","parentId":"3-1-1","children":[]}
]},
{"label":"3-1-2","value":"3-1-2","parentId":"3-1","children":[
{"label":"3-1-2-1","value":"3-1-2-1","parentId":"3-1-2","children":[]}
]}
]},
{"label":"3-2","value":"3-2","parentId":"3","children":[]}
]},
{"label":'2',"value":"2","children":[
{"label":"2-1","value":"2-1","parentId":"2","children":[]}
]}
];
/*
* data:array 类目结构的数据,数组内部元素为对象
* appointLevel:number 所要获取到数据的截止层级
*/
const getAppointLevelCategoryData = (data, appointLevel, currentLevel = 1) => {
const newData = [];
data.forEach(item => {
let obj = {};
if (Array.isArray(item.children) && item.children.length > 0) {
if (currentLevel < appointLevel) {
const tempData = getAppointLevelCategoryData(item.children, appointLevel, currentLevel + 1);
obj = {
...item,
children: tempData,
};
} else {
obj = {
...item,
children: [],
};
}
} else {
obj = {
...item,
};
}
newData.push(obj);
});
return newData;
}
console.log(JSON.stringify(
getAppointLevelCategoryData(categoryData, 2),
null,
2
))
获取指定层级的所有内容
const categoryData = [
{"label":'1',"value":"1","children":[
{"label":"1-1","value":"1-1","parentId":"1","children":[
{"label":"1-1-1","value":"1-1-1","parentId":"1-1","children":[]}
]}
]},
{"label":'3',"value":"3","children":[
{"label":"3-1","value":"3-1","parentId":"3","children":[
{"label":"3-1-1","value":"3-1-1","parentId":"3-1","children":[
{"label":"3-1-1-1","value":"3-1-1-1","parentId":"3-1-1","children":[]}
]},
{"label":"3-1-2","value":"3-1-2","parentId":"3-1","children":[
{"label":"3-1-2-1","value":"3-1-2-1","parentId":"3-1-2","children":[]}
]}
]},
{"label":"3-2","value":"3-2","parentId":"3","children":[]}
]},
{"label":'2',"value":"2","children":[
{"label":"2-1","value":"2-1","parentId":"2","children":[]}
]}
];
/*
* data:array 类目结构的数据,数组内部元素为对象
* appointLevel:number 所要获取到数据的截止层级
*/
const getAppointLevelAllData = (data, appointLevel) => {
const newData = [];
const deep = (innerData, level) => {
innerData.forEach(item => {
if (level === appointLevel) {
newData.push(item);
}
if (Array.isArray(item.children) && item.children.length > 0 && level < appointLevel) {
deep(item.children, level + 1);
}
});
};
deep(data, 1);
return newData;
}
console.log(getAppointLevelAllData(categoryData, 3));
获取所有层级的内容
const categoryData = [
{"label":'1',"value":"1","children":[
{"label":"1-1","value":"1-1","parentId":"1","children":[
{"label":"1-1-1","value":"1-1-1","parentId":"1-1","children":[]}
]}
]},
{"label":'3',"value":"3","children":[
{"label":"3-1","value":"3-1","parentId":"3","children":[
{"label":"3-1-1","value":"3-1-1","parentId":"3-1","children":[
{"label":"3-1-1-1","value":"3-1-1-1","parentId":"3-1-1","children":[]}
]},
{"label":"3-1-2","value":"3-1-2","parentId":"3-1","children":[
{"label":"3-1-2-1","value":"3-1-2-1","parentId":"3-1-2","children":[]}
]}
]},
{"label":"3-2","value":"3-2","parentId":"3","children":[]}
]},
{"label":'2',"value":"2","children":[
{"label":"2-1","value":"2-1","parentId":"2","children":[]}
]}
];
/*
* data:array 类目结构的数据,数组内部元素为对象
*/
const getAllData = data => {
if (Array.isArray(data) && data.length > 0) {
const allData = [];
const deep = innerData => {
innerData.forEach(item => {
allData.push(item);
if (Array.isArray(item.children) && item.children.length > 0) {
deep(item.children);
}
});
};
deep(data);
return allData;
} else {
return [];
}
}
console.log(getAllData(categoryData));
指定一个id找到对应节点的祖先节点id
const categoryData = [
{"label":'1',"value":"1","children":[
{"label":"1-1","value":"1-1","parentId":"1","children":[
{"label":"1-1-1","value":"1-1-1","parentId":"1-1","children":[]}
]}
]},
{"label":'3',"value":"3","children":[
{"label":"3-1","value":"3-1","parentId":"3","children":[
{"label":"3-1-1","value":"3-1-1","parentId":"3-1","children":[
{"label":"3-1-1-1","value":"3-1-1-1","parentId":"3-1-1","children":[]}
]},
{"label":"3-1-2","value":"3-1-2","parentId":"3-1","children":[
{"label":"3-1-2-1","value":"3-1-2-1","parentId":"3-1-2","children":[]}
]}
]},
{"label":"3-2","value":"3-2","parentId":"3","children":[]}
]},
{"label":'2',"value":"2","children":[
{"label":"2-1","value":"2-1","parentId":"2","children":[]}
]}
];
/*
* data:array 类目结构的数据,数组内部元素为对象
* value: 简单数据类型 所要查找属性的值
* uniqueKey:string 所要查找的属性
*/
const findParentId = (data, value, uniqueKey) => {
const path = []; // 从祖先到指定节点的数组
let findFlag = false;
const deep = (array, innerValue) => {
array.forEach(item => {
if (findFlag) return;
path.push(item.value); // 每一次循环都将value push到数组中
if (item[uniqueKey] === innerValue) {
findFlag = true;
} else if (Array.isArray(item.children) && item.children.length) {
deep(item.children, innerValue);
} else {
path.pop(); // 如果是最后一层且不相同则将刚push进去的值去除
}
});
if (!findFlag) {
path.pop(); // 当有children时调用deep函数结束时且还是没有找到相同的id则将有children的item的value从path中去除
}
};
deep(data, value);
return path;
}
console.log(findParentId(categoryData, '3-1-1-1', 'value'));
统计类目结构数据相同层级的数量
const categoryData = [
{"label":'1',"value":"1","children":[
{"label":"1-1","value":"1-1","parentId":"1","children":[
{"label":"1-1-1","value":"1-1-1","parentId":"1-1","children":[]}
]}
]},
{"label":'3',"value":"3","children":[
{"label":"3-1","value":"3-1","parentId":"3","children":[
{"label":"3-1-1","value":"3-1-1","parentId":"3-1","children":[
{"label":"3-1-1-1","value":"3-1-1-1","parentId":"3-1-1","children":[]}
]},
{"label":"3-1-2","value":"3-1-2","parentId":"3-1","children":[
{"label":"3-1-2-1","value":"3-1-2-1","parentId":"3-1-2","children":[]}
]}
]},
{"label":"3-2","value":"3-2","parentId":"3","children":[]}
]},
{"label":'2',"value":"2","children":[
{"label":"2-1","value":"2-1","parentId":"2","children":[]}
]}
];
/*
* data:array 类目结构的数据,数组内部元素为对象
*/
const getLevelCount = data => {
if (Array.isArray(data) && data.length > 0) {
const levelData = {};
const deep = (innerData, level) => {
return innerData.forEach(item => {
typeof(levelData[level]) === 'undefined' ? levelData[level] = 1 : levelData[level] += 1;
if (item.children && item.children.length > 0) {
deep(item.children, level + 1);
}
});
};
deep(data, 1);
return levelData;
} else {
return {};
}
}
console.log(getLevelCount(categoryData));
操作类目结构数据添加当前项是该层级的第几项
const categoryData = [
{"label":'1',"value":"1","children":[
{"label":"1-1","value":"1-1","parentId":"1","children":[
{"label":"1-1-1","value":"1-1-1","parentId":"1-1","children":[]}
]}
]},
{"label":'3',"value":"3","children":[
{"label":"3-1","value":"3-1","parentId":"3","children":[
{"label":"3-1-1","value":"3-1-1","parentId":"3-1","children":[
{"label":"3-1-1-1","value":"3-1-1-1","parentId":"3-1-1","children":[]}
]},
{"label":"3-1-2","value":"3-1-2","parentId":"3-1","children":[
{"label":"3-1-2-1","value":"3-1-2-1","parentId":"3-1-2","children":[]}
]}
]},
{"label":"3-2","value":"3-2","parentId":"3","children":[]}
]},
{"label":'2',"value":"2","children":[
{"label":"2-1","value":"2-1","parentId":"2","children":[]}
]}
];
/*
* data:array 类目结构的数据,数组内部元素为对象
*/
const mapCategoryDataWithLevelInfo = data => {
if (Array.isArray(data) && data.length > 0) {
const levelData = {};
const deep = (innerData, level = 1) => {
const newData = [];
innerData.forEach(item => {
typeof(levelData[level]) === 'undefined' ? levelData[level] = 1 : levelData[level] += 1;
let obj = {
...item,
sameLevelSort: levelData[level], // 当前项是该层级中的第几个
currentLevel: level, // 当前项属于的层级
};
if (Array.isArray(item.children) && item.children.length > 0) {
const tempData = deep(item.children, level + 1);
obj.children = tempData;
}
newData.push(obj);
});
return newData;
};
return deep(data);
} else {
return [];
}
}
console.log(JSON.stringify(mapCategoryDataWithLevelInfo(categoryData), null, 2))
为tree数据添加唯一key属性(key和当前顺序以及层次相关,适用于tree节点可以动态添加或拖拽且key不能重复的情况)
const categoryData = [
{"label":'1',"value":"1","children":[
{"label":"1-1","value":"1-1","parentId":"1","children":[
{"label":"1-1-1","value":"1-1-1","parentId":"1-1","children":[]}
]}
]},
{"label":'3',"value":"3","children":[
{"label":"3-1","value":"3-1","parentId":"3","children":[
{"label":"3-1-1","value":"3-1-1","parentId":"3-1","children":[
{"label":"3-1-1-1","value":"3-1-1-1","parentId":"3-1-1","children":[]}
]},
{"label":"3-1-2","value":"3-1-2","parentId":"3-1","children":[
{"label":"3-1-2-1","value":"3-1-2-1","parentId":"3-1-2","children":[]}
]}
]},
{"label":"3-2","value":"3-2","parentId":"3","children":[]}
]},
{"label":'2',"value":"2","children":[
{"label":"2-1","value":"2-1","parentId":"2","children":[]}
]}
];
/*
* data:array 类目结构的数据,数组内部元素为对象
* parentKey: 当前数据节点的父节点的key
*/
const addUniqueTreeKey = (data, parentKey) => {
const newData = []
data.forEach((item, index) => {
const newKey = parentKey ? `${parentKey}-${index + 1}` : `${index + 1}`
const obj = { ...item, key: newKey, parentKey: parentKey || null }
if (Array.isArray(item.children) && item.children.length > 0) {
const tempData = addUniqueTreeKey(item.children, newKey)
obj.children = tempData
}
newData.push(obj)
})
return newData
}
console.log(JSON.stringify(addUniqueTreeKey(categoryData), null, 2))
判断某一个id是否为最后一层的id
const categoryData = [
{"label":'1',"value":"1","children":[
{"label":"1-1","value":"1-1","parentId":"1","children":[
{"label":"1-1-1","value":"1-1-1","parentId":"1-1","children":[]}
]}
]},
{"label":'3',"value":"3","children":[
{"label":"3-1","value":"3-1","parentId":"3","children":[
{"label":"3-1-1","value":"3-1-1","parentId":"3-1","children":[
{"label":"3-1-1-1","value":"3-1-1-1","parentId":"3-1-1","children":[]}
]},
{"label":"3-1-2","value":"3-1-2","parentId":"3-1","children":[
{"label":"3-1-2-1","value":"3-1-2-1","parentId":"3-1-2","children":[]}
]}
]},
{"label":"3-2","value":"3-2","parentId":"3","children":[]}
]},
{"label":'2',"value":"2","children":[
{"label":"2-1","value":"2-1","parentId":"2","children":[]}
]}
];
/*
* data:array 类目结构的数据,数组内部元素为对象
* value: 简单数据类型 所要判断属性的值
* uniqueKey:string 所要判断的属性
*/
const isLastLevelKey = (data, value, uniqueKey) => {
if (Array.isArray(data) && data.length > 0 && value && uniqueKey) {
let flag = false;
const deep = innerData => {
return innerData.some(item => {
if (item[uniqueKey] === value) {
if (!item.children || item.children.length === 0) {
flag = true;
return true;
} else {
return true;
}
} else if (item.children && item.children.length > 0) {
return deep(item.children);
}
});
};
deep(data);
return flag;
} else {
return false;
}
};
console.log(isLastLevelKey(categoryData, '3-1-1-1', 'value'));
获取所有最后一级的数据
const categoryData = [
{"label":'1',"value":"1","children":[
{"label":"1-1","value":"1-1","parentId":"1","children":[
{"label":"1-1-1","value":"1-1-1","parentId":"1-1","children":[]}
]}
]},
{"label":'3',"value":"3","children":[
{"label":"3-1","value":"3-1","parentId":"3","children":[
{"label":"3-1-1","value":"3-1-1","parentId":"3-1","children":[
{"label":"3-1-1-1","value":"3-1-1-1","parentId":"3-1-1","children":[]}
]},
{"label":"3-1-2","value":"3-1-2","parentId":"3-1","children":[
{"label":"3-1-2-1","value":"3-1-2-1","parentId":"3-1-2","children":[]}
]}
]},
{"label":"3-2","value":"3-2","parentId":"3","children":[]}
]},
{"label":'2',"value":"2","children":[
{"label":"2-1","value":"2-1","parentId":"2","children":[]}
]}
];
/*
* data:array 类目结构的数据,数组内部元素为对象
*/
const getLastLevelData = data => {
if (Array.isArray(data) && data.length > 0) {
const newData = [];
const deep = innerData => {
innerData.forEach(item => {
if (Array.isArray(item.children) && item.children.length > 0) {
deep(item.children);
} else {
newData.push(item);
}
});
};
deep(data);
return newData;
} else {
return [];
}
}
console.log(getLastLevelData(categoryData));