最近实际开发过程中经常遇到需要处理树形数据结构,每次都要写一遍递归,感觉比较麻烦,各个组员的写法也不统一,于是想自己写一套终极版本,希望能够兼顾复杂的业务场景和代码执行效率直接上代码和大家分享一下,欢迎指正。
/**
*
* @param {Array} tree [{label,value,children}]
* @param {Object} option
* {
* labelKey String 将转换为label的键 default:'label'
* valueKey String 将转换为value的键 default:'value'
* childrenKey String 将转换为children的键 default:'children'
* clean Boolean 是否剔除其余属性,default:true
* getValue Function 用于获取value的函数,传入当前节点,优先级高于valueKey default:undefind
* getLabel Function 用于获取label的函数,传入当前节点,优先级高于labelKey default:undefind
* getChildren Function 用于获取label的函数,传入当前节点,优先级高于childrenKey default:undefind
* deep Number 转化树结构的深度,为0时转化所有,默认为0 default:0
* }
* @param {Array} result 目标数组,不用传 default:[]
* 此方法不会修改原数据,会返回一个新的数组
* example:
* initTree(data, { labelKey: 'region_name', valueKey: 'national_code', childrenKey: 'childn_ational' })
*/
export const initTree = (tree, option, result = []) => {
const { labelKey = 'label', valueKey = 'value', childrenKey = 'children', clean = true, getValue, getLabel, getChildren, deep = 0 } = option;
for (let i = 0; i < tree.length; i++) {
result[i] = {
label: getLabel ? getLabel(tree[i]) : tree[i][labelKey],
value: getValue ? getValue(tree[i]) : tree[i][valueKey],
};
if (!clean) {
result[i] = { ...tree[i], ...result[i] };
}
const _children = getChildren ? getChildren(tree[i]) : tree[i][childrenKey];
if (deep !== 1 && _children && _children.length) {
result[i].children = [];
initTree(
_children,
deep > 1 ? { ...option, deep: option.deep - 1 } : option,
result[i].children
);
}
}
/**
* 遍历树结构,fn一旦返回false就会停止遍历
* @param {Array} tree 树结构
* @param {Function} fn 对每个节点执行一遍fn方法
* @param {String} childrenKey 作为children的键
*/
export const treeForEach = (tree, fn, childrenKey = 'children') => {
for (let i = 0; i < tree.length; i++) {
if (fn(tree[i]) === false) return false;
if (
tree[i][childrenKey]
&& tree[i][childrenKey].length
&& treeForEach(tree[i][childrenKey], fn) === false
) return false;
}
};
/**
* 从树结构里根据value找到第一个结点
* @param {*} value
* @param {Array} tree [{label,value,children}]
*/
export const findNodeByValue = (tree, value) => {
let result;
treeForEach(tree, (node) => {
if (node.value === value) {
result = node;
return false;
}
});
return result;
};
/**
* 从树结构里根据label找到第一个结点
* @param {*} value
* @param {Array} tree [{label,value,children}]
*/
export const findNodeByLabel = (tree, label) => {
let result;
treeForEach(tree, (node) => {
if (node.label === label) {
result = node;
return false;
}
});
return result;
};
return result;
};