>[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);
}
}
}
}
}
```