功能描述
filterSelectedIds
函数用于过滤选中的 ID,确保如果一个父节点的所有子节点没有全部被选中,则从选中集合中移除该父节点的 ID。
场景
【antd】Tree组件子节点不完全勾选获取父节点的值 - 简书 React antd Tree组件子节点不完全勾选获取父节点的值 - 知乎
参数
selectedIds
:一个包含选中 ID 的字符串数组。treeData
:一个包含树形结构数据的对象数组。每个节点对象包含以下属性:id
:节点的唯一 ID(字符串类型)。code
:节点的代码(可选,字符串类型)。name
:节点的名称(字符串类型)。childPermissionList
:子节点列表(可选,数组类型)。
返回值
- 返回一个过滤后的选中 ID 数组。
使用示例
示例数据
假设我们有如下选中的 ID 和树形结构数据:
const selectedIds = [
'id1', // 父节点 ID
'id2', // 子节点 ID
'id5', // 孙子节点 ID
'id7', // 子节点 ID
];
const treeData = [
{
id: 'id1',
code: 'Code1',
name: '节点1',
childPermissionList: [
{
id: 'id2',
code: 'Code2',
name: '节点2',
childPermissionList: [
{
id: 'id5',
code: 'Code5',
name: '节点5',
childPermissionList: [],
},
{
id: 'id6',
code: 'Code6',
name: '节点6',
childPermissionList: [],
}
],
},
{
id: 'id3',
code: 'Code3',
name: '节点3',
childPermissionList: [
{
id: 'id4',
code: 'Code4',
name: '节点4',
childPermissionList: [],
},
],
},
],
},
{
id: 'id7',
code: 'Code7',
name: '节点7',
childPermissionList: [
{
id: 'id8',
code: 'Code8',
name: '节点8',
childPermissionList: [],
},
],
},
];
示例调用
const filteredIds = filterSelectedIds(selectedIds, treeData);
console.log(filteredIds); // 输出: ['id2', 'id5', 'id7']
在这个示例中,父节点 id1
有两个子节点 id2
和 id3
。子节点 id2
有两个子节点 id5
和 id6
。选中的 ID 中包含了 id1
、id2
、id5
和 id7
,但没有包含 id6
和 id3
的 ID。因此,id1
被移除,只保留 id2
和 id5
以及单独的 id7
。
代码实现
以下是包含中文注释的 filterSelectedIds
函数实现:
/**
* 过滤选中的 ID,移除那些子节点未完全选中的父节点 ID。
*
* @param {string[]} selectedIds - 选中的 ID 数组。
* @param {Object[]} treeData - 树形结构数据。
* @param {string} treeData[].id - 节点的唯一 ID。
* @param {string} [treeData[].code] - 节点的代码。
* @param {string} treeData[].name - 节点的名称。
* @param {Object[]} [treeData[].childPermissionList] - 子节点列表。
*
* @returns {string[]} - 过滤后的选中 ID 数组。
*
* @example
* const selectedIds = [
* 'id1', // 父节点 ID
* 'id2', // 子节点 ID
* 'id5', // 孙子节点 ID
* 'id7', // 子节点 ID
* ];
*
* const treeData = [
* {
* id: 'id1',
* code: 'Code1',
* name: '节点1',
* childPermissionList: [
* {
* id: 'id2',
* code: 'Code2',
* name: '节点2',
* childPermissionList: [
* {
* id: 'id5',
* code: 'Code5',
* name: '节点5',
* childPermissionList: [],
* },
* {
* id: 'id6',
* code: 'Code6',
* name: '节点6',
* childPermissionList: [],
* }
* ],
* },
* {
* id: 'id3',
* code: 'Code3',
* name: '节点3',
* childPermissionList: [
* {
* id: 'id4',
* code: 'Code4',
* name: '节点4',
* childPermissionList: [],
* },
* ],
* },
* ],
* },
* {
* id: 'id7',
* code: 'Code7',
* name: '节点7',
* childPermissionList: [
* {
* id: 'id8',
* code: 'Code8',
* name: '节点8',
* childPermissionList: [],
* },
* ],
* },
* ];
*
* const filteredIds = filterSelectedIds(selectedIds, treeData);
* console.log(filteredIds); // 输出: ['id2', 'id5', 'id7']
*/
/**
* 递归检查当前节点的所有子节点是否都被选中。
* 如果没有,则从选中集合中移除父节点 ID。
*
* @param {Object} node - 当前节点。
* @param {string} node.id - 节点的唯一 ID。
* @param {Object[]} [node.childPermissionList] - 子节点列表。
*/
const filterSelectedIds = (selectedIds, treeData) => {
// 创建一个包含选中 ID 的 Set
const selectedSet = new Set(selectedIds);
/**
* 递归函数,检查并移除未完全选中的父节点 ID。
*
* @param {Object} node - 当前节点。
*/
const checkAndRemoveParentId = (node) => {
// 如果当前节点有子节点列表且不为空
if (node.childPermissionList && node.childPermissionList.length > 0) {
// 假设当前节点的所有子节点都被选中
let allChildrenSelected = true;
// 遍历当前节点的子节点列表
for (let child of node.childPermissionList) {
// 如果当前子节点未被选中
if (!selectedSet.has(child.id)) {
// 将假设设为 false,并跳出循环
allChildrenSelected = false;
break;
}
}
// 如果不是所有子节点都被选中
if (!allChildrenSelected) {
// 从选中集合中移除当前节点的 ID
selectedSet.delete(node.id);
}
// 对当前节点的每个子节点递归调用此函数
node.childPermissionList.forEach(checkAndRemoveParentId);
}
};
// 对树形数据的每个根节点调用递归函数
treeData.forEach(checkAndRemoveParentId);
// 将 Set 转换为数组并返回
return Array.from(selectedSet);
};
常见问题
为什么需要这个函数?
在处理树
形结构数据时,我们通常需要确保只有当父节点的所有子节点都被选中时,父节点才会被认为是选中的。这个函数通过移除那些子节点未完全选中的父节点,确保选中集合的准确性。
如果树结构中没有子节点,该函数会如何处理?
如果节点没有子节点,该节点的选中状态不会受到影响。只有那些包含子节点的节点才会受到函数的处理和检查。
这个函数是否会修改原始数据?
不会。该函数不会修改原始的 selectedIds
数组和 treeData
对象数组,而是创建并返回一个新的选中 ID 数组。