[搜索前樹狀展現] 後端
[搜索關鍵字"測試"] 數組
遍歷扁平化節點,逐一尋找其父節點,並插入。bash
同時判斷是否根節點,如果直接抽出根節點。數據結構
須要遍歷兩次數據:構造以id爲索引的對象、尋找父節點據。性能
(根節點parent === '0')測試
/**
* 扁平結構轉成樹狀結構
* @param category 扁平數據
*/
formateTree = (category) => {
const treeMap = {} // 以id爲索引的對象
const tree = [] // 最後樹狀結果
category.forEach((o) => {
treeMap[o.id] = Object.assign(o, { children: [] }
})
category.forEach((o) => {
if (o.parent !== '0') {
treeMap[o.parent].children.push(treeMap[o.id])
} else if (o.parent === '0') {
tree.push(treeMap[o.id])
}
})
return tree
}
複製代碼
1.【遞歸】根據關鍵字遍歷樹狀結構尋找各路徑下第一命中節點 findTargetNode() ,並插入filterNode[],將節點parent 插入expandedList[]。ui
命中標記:⭐spa
2.【遞歸】展開非子節點下包含關鍵字節點的路徑 findExpandedNode() ,將命中節點parent 插入expandedLish[]。3d
⚠️ 注意,如中間有兩層以上沒有命中關鍵字,則沒法展開,最後須要根據expandedList[] 中的節點向上補齊 insertNodeParent() 。code
3.【遞歸】尋找命中節點的父節點,拼接成樹 findParend() 。
4.expandedList[] 去重。
【遞歸】根據filterNode[] 中的節點向上補齊已展開節點的各級父節點,用到索引對象 insertNodeParent()。
5.原理同3
6.expandedList[] 去重。
findTargetNode()
第一命中節點爲末節點時:插入(將該節點push 進filterNode[] ),展開(並將其父id push 到expandedList[] )。
第一命中節點爲非子節點時:插入,並須要遍歷該路徑繼續尋找剩餘命中節點 findExpandedNode() 。
const findTargetNode = (val, tree, filterNode, expandedList) => {
tree.forEach((item) => {
if (item.title.indexOf(val) > -1) {
if (!item.children.length) {
filterNode.push(item);
expandedList.push(item.parent);
} else {
filterNode.push(item);
expandedList.push(item.parent);
findExpandedNode(val, tree, expandedList);
}
} else {
findTargetNode(val, item.children, filterNode, expandedList);
}
})
}
複製代碼
findExpandedNode()
末節點包含關鍵字:展開;不包含:不處理。
非末節點包含關鍵字:展開,繼續遞歸;不包含:繼續遞歸。
const findExpandedNode = (val, tree, expandedList) => {
tree.forEach((item) => {
if (!item.children.length && item.title.indexOf(val) > -1) {
expandedList.push(item.parent);
} else if (item.children.length && item.title.indexOf(val) > -1) {
expandedList.push(item.parent);
findExpandedNode(val, item.children, expandedList)
} else if (item.children.length && item.title.indexOf(val) === -1) {
findExpandedNode(val, item.children, expandedList)
}
})
}
複製代碼
findParend()
父節點不是根節點
目前對象樹中父節點是否已包含該節點,包含:不梳理;未包含:插入父節點。(避免重複)
複製代碼
父節點爲根節點
目前結果中,是否已包含該根節點,包含:不處理;未包含:插入結果中。
複製代碼
const findParend = (item, treeMap, treeData, expandedList) => {
if (item.parent !== '0') {
const ids = treeMap[item.parent].children.map(o => o.id);
if (!ids.includes(item.id)) {
treeMap[item.parent].children.push(item);
expandedList.push(item.parent);
findParend(treeMap[item.parent], treeMap, treeData, expandedList);
}
} else {
const ids = treeData.map(o => o.id);
if (!ids.includes(item.id)) {
treeData.push(item);
expandedList.push(item.id)
}
}
}
複製代碼
expandedList[] 去重
Es6 set數據結構
expandedList = [...new Set(expandedList)]
複製代碼
insertNodeParent()
當前節點爲非根節點時,插入該節點父id
當前節點爲根節點時,返回
const insertNodeParent = (key, expandedList, treeMap) => {
if (key === '0') {
return
}
const { parent } = treeMap[key]
expandedList.push(parent)
if (parent !== '0') {
insertNodeParent(parent, expandedList, treeMap)
}
}
複製代碼