>[info]該方法是在營銷平臺一期開發中,根據需求,在選中區劃后需要將選中的區劃回顯在前臺頁面時開發的遞歸查找節點數據的函數方法。
下面第一個方法是提供給外層調用的配置尋找目標的方法,具體配置項若下
#### API文檔
| 參數 | 數據類型 | 是否必填 | 默認值 | 備注 |
|:---:|:---:|:---:|:---:|:---:|
| dataSource | Array | Y | - | 遍歷查找目標數據所在位置的源數據
| targetNode | String | Y | - | 需要查找的目標節點的數據
| options | Object | N | 參照下方 | 查找的配置項
| options - compareKey | String | N | code | 需要對比區劃數據的key值,默認對比code
| options - changeDataSource | bool | N | false | 查找時是否使用源數據查找,如果使用源數據查找,修改源數據后所有指向該數據的地方均會產生視圖上的響應
| options - operateFn | Func | N | - | 查找到目標數據后執行的邏輯操作
| options - returnKeys | Array[string] | N | - | 查找到目標數據后返回的數據格式,默認返回查找到的源數據
```javascript
// 查找目標區劃結果
let resultNode = null;
/**
* 查找目標區劃方法
* @param {*} dataSource 遍歷查找的數據,必填
* @param {*} targetNode 查找的目標節點,必填
* @param options 查找配置項,非必填,默認對比code且不修改源數據
*/
export const findTargetDistrict = (dataSource, targetNode, options) => {
resultNode = null;
options = {
changeDataSource: false,
compareKey: 'code',
...options,
};
const { changeDataSource, operateFn, returnKeys, compareKey } = options;
dataSource = !changeDataSource ? [].concat(dataSource) : dataSource;
if (!Array.isArray(dataSource)) {
console.error('傳入的原始數據類型錯誤');
return false;
}
if (!targetNode) {
console.error('傳入的目標節點數據有誤,如需查找所有節點,請使用其他方法');
return false;
}
RecursionFindTargetNode(dataSource, targetNode, {
compareKey,
operateFn,
});
/**
* 處理要返回的數據格式
* returnKeys為空時返回全部節點
* 否則遍歷returnKeys,將對應的數據放到處理后的數據中,將處理后的數據返回
*/
if (returnKeys && resultNode) {
const handledNodeData = {};
for (const key of returnKeys) {
handledNodeData[key] = resultNode[key];
}
return handledNodeData;
}
return resultNode || '未查找到目標數據,請確認參數是否正確';
};
```
第二個方法是在查找目標數據過程中實際調用的遞歸方法,因為**遞歸的數據在每一層長度都不是固定的**,因此需要保留之前的調用棧的記錄,不能簡單粗暴的直接使用尾遞歸調用優化程序,**需要根據情況去判斷是否需要保留目前的棧**。同時因為**保留了之前的調用記錄一次break并不能直接清除所有的調用記錄**,所以需要在每次進行遞歸之前進行判斷是否已經查找到了目標節點來減少
```javascript
/**
* 遞歸查找子節點方法
* @param {*} dataSource 遞歸查找的數據
* @param {*} targetNode 目標節點數據
* @param {*} options 查找的配置項
*/
function RecursionFindTargetNode(dataSource, targetNode, options) {
if (!resultNode) {
const { compareKey, operateFn } = options;
const dataSourceLen = dataSource.length;
for (let index = 0; index < dataSourceLen; index += 1) {
const currentNode = dataSource[index];
if (currentNode[compareKey] === targetNode) {
operateFn && operateFn(currentNode);
resultNode = currentNode;
break;
} else if (currentNode.children && !!currentNode.children.length && !resultNode) {
/**
* 如果當前節點存在葉子節點,繼續遞歸葉子節點
* 這里面存在一個判斷,如果當前遍歷的dataSource長度為1,則使用尾遞歸優化,釋放之前的保留的隊列
* 如果不為1,需要保留當前的隊列
*/
if (dataSourceLen === 1) {
return RecursionFindTargetNode(currentNode.children, targetNode, options);
} else {
RecursionFindTargetNode(currentNode.children, targetNode, options);
}
}
}
}
}
```