tree 的递归算法
tree的数据结构: tree = [ { check: false, children: [ check: false, children: [ { { check: false, children: [ { check: false, children: [], code: "SD2016082600160", disabled: false, isLeaf: true, label: "金泰荔湾小区", name: "金泰荔湾小区", open: false, orgLeaf: false, parentCode: "O04464422616", parentName: "测试超长字段的组织", projectCodeList: [] } ], code: "O04464422616" disabled: false, isLeaf: false, label: "测试超长字段的组织", name: "测试超长字段的组织", open: false, orgLeaf: true, parentCode: "080311bbbe8642899d325742b2073805", projectCodeList: ["SD2016082600160"] }, { check: false, children: [], code: "SD2016082600170", disabled: false, isLeaf: true, label: "高德公寓", name: "高德公寓", open: false, orgLeaf: false, parentCode: "080311bbbe8642899d325742b2073805", parentName: "集中管控标准版", projectCodeList: [] } }, { check: false, children: [], code: "p201809211", disabled: false, isLeaf: true, label: "集中管控测试项目", name: "集中管控测试项目", open: false, orgLeaf: false, parentCode: "fb3087611f248d93d67330b4938fff8e", parentName: "集中管控多项目集团", projectCodeList: [] } ], code: "080311bbbe8642899d325742b2073805", disabled: false, isLeaf: false, label: "集中管控标准版", name: "集中管控标准版", open: false, orgLeaf: false, parentCode: "fb3087611f248d93d67330b4938fff8e", projectCodeList: ["SD2016082600170"] ], code: "fb3087611f248d93d67330b4938fff8e", disabled: false, isLeaf: false, label: "集中管控多项目集团", name: "集中管控多项目集团", open: false, orgLeaf: false, projectCodeList: ["p201811081", "p201809211", SD2016082600190", "SD2016082600164", "SD2016082600196",…] } ]
1.根据code ,寻找tree里面的选中对象
export function getActiveNode(tree,code){ tree: [{}] // 树型结构 let node = {}; finds(tree,code); function finds(tree,code) { for(let i=0;i<tree.length;i++){ if(tree[i].code == code){ node = tree[i] } else { if(tree[i].children && tree[i].children.length>0){ finds(tree[i].children,code) } } } } return node; }
2. 通过code筛选组织树节点,输出 [{}]
export function filterNode (tree, code) { if (!code) {return} let resultArr = [] for (let i = 0; i < tree.length; i++) { let item = tree[i] if (item.code == code) { resultArr.push(item) return resultArr } else if (item.children && item.children.length) { resultArr = filterNode(item.children, code) } } return resultArr }
2.1 通过code找到对应节点,输出{}
let findNode = function (arr, code) { for (let i = 0, len = arr.length; i < len; i++) { let syncNode = arr[i] if(syncNode.path == code){ return syncNode; } if (syncNode.children && syncNode.children.length) { const foundNode = findNode(syncNode.children, code) if (foundNode) { return foundNode } } } return null }
findNode (arr, code)
3.有父子关系的数组转换成树形结构的数组
/** * 该方法用于将有父子关系的数组转换成树形结构的数组 * 接收一个具有父子关系的数组作为参数 * 返回一个树形结构的数组 */ export function translateDataToTree (data) { let parents = data.filter((item,index) => {return index === data.length-1}) //有父节点的数据 let childrens = data.filter(value => value.parentCode) //定义转换方法的具体实现 let translator = (parents, childrens) => { parents.forEach((parent) => { childrens.forEach((current, index) => { if (current.parentCode === parent.code) { //对子节点数据进行深复制,这里只支持部分类型的数据深复制,对深复制不了解的童靴可以先去了解下深复制 let temp = JSON.parse(JSON.stringify(childrens)) //让当前子节点从temp中移除,temp作为新的子节点数据,这里是为了让递归时,子节点的遍历次数更少,如果父子关系的层级越多,越有利 temp.splice(index, 1) //让当前子节点作为唯一的父节点,去递归查找其对应的子节点 translator([current], temp) //把找到子节点放入父节点的childrens属性中 typeof parent.children !== 'undefined' ? parent.children.push(current) : parent.children = [current] } }) }) } //调用转换方法 translator(parents, childrens) //返回最终的结果 console.log(parents) return parents }
4. 递归获取第一个节点下面的第一个叶子节点
// 查找一个树第一个节点的第一个叶子节点,深度遍历
getFirstNode (tree) { var temp = {} var forFn = function (arr) { if (arr && arr.length > 0) { temp = arr[0] if (arr[0].children) { forFn(arr[0].children) } } } forFn(tree) return temp }
// 遍历,获取第一个子元素下面的叶子节点,如果没有叶子节点,则去children里面找,依次类推,知道找到位置
getFirstNode (data) {
let node = {}
let forFn = (data) => {
data.forEach(el => {
if (el.isLeaf) {
node = el
} else if (el.children && el.children.length) {
if (el.children.findIndex(v => v.isLeaf) > -1) {
node = el.children.find(v => v.isLeaf)
} else {
forFn(el.children)
}
}
})
}
forFn(data)
return node
},
5. 递归获取第一个节点下面的所有的第一个节点
// 查找一个树多个第一个节点,深度遍历 getFirstNode (tree) { var temp = [] var forFn = function (arr) { if (arr && arr.length > 0) { temp.push(arr[0]) if (arr[0].children) { forFn(arr[0].children) } } } forFn(tree) return temp }
6. 递归删除树结构所有的叶子节点
// 删除树结构所有叶子节点 treeDataHandle(tree) { let newArr = []; for (let i = 0; i < tree.length; i++){ let item = tree[i]; if(item.isLeaf === true) { tree.splice(i--, 1); // 这里不可用delete,会有语法报错,i--,是删掉第i个后,索引需要减1 } else { if (item.children && item.children.length) { item.children = this.treeDataHandle(item.children); } newArr.push(item); } } // console.log('最终处理的结果', newArr) return newArr }
7. 递归给树结构每一项添加 value, label,children 属性,chils 数组为空,不添加children
export function addPropertys (tree) { let forFn = function (arr) { arr.forEach(item => { // 此刻arr.forEach改变了预原数组的值arr,所以直接返回出去了arr,原因是 Object.assign(item, {}),这里是直接改变了item的值,item没有重新指向,如果使用 item = Obejct.assign({}, item, {}),item重新指向后,arr值就不会改变了 if (item.childs && item.childs.length) { forFn(item.childs) } item.childs && item.childs.length? Object.assign(item,{value: item.areaId, label: item.name, children: item.childs}):Object.assign(item,{value: item.areaId, label: item.name}) }) return arr } let result = forFn(tree) return result }
备注:forEach 会不会改变原数组 查看 原理