在处理树形数据时,如果需要过滤掉 id
为某些特定值的项(包括这些项的子节点),可以通过递归遍历树形数据来实现。假设树形数据结构中每个节点的子节点字段为 children
,以下是几种实现方法:
方法 1:递归过滤
使用递归函数遍历树,检查每个节点的 id
,如果匹配需要过滤的值,则移除该节点及其子节点。
javascript
// 假设树形数据
const treeData = [
{ id: 1, name: '节点1', children: [{ id: 11, name: '节点1-1' }] },
{ id: 2, name: '节点2', children: [{ id: 21, name: '节点2-1' }] },
{ id: 3, name: '节点3' }
];
// 需要过滤的 id 数组
const filterIds = [2, 11];
// 递归过滤函数
function filterTree(data, filterIds) {
return data.filter(node => {
// 如果当前节点的 id 在过滤列表中,直接排除
if (filterIds.includes(node.id)) {
return false;
}
// 如果有子节点,递归过滤子节点
if (node.children && node.children.length > 0) {
node.children = filterTree(node.children, filterIds);
}
return true;
});
}
// 执行过滤
const filteredTree = filterTree(treeData, filterIds);
console.log(JSON.stringify(filteredTree, null, 2));
输出结果:
json
[
{
"id": 1,
"name": "节点1",
"children": []
},
{
"id": 3,
"name": "节点3"
}
]
说明:
filterIds
包含需要移除的id
(例如[2, 11]
)。filterTree
函数递归遍历树,遇到匹配id
的节点直接返回false
(移除),并对子节点递归处理。
方法 2:深拷贝后过滤(避免修改原数据)
如果不希望修改原始数据,可以先深拷贝一份数据再进行过滤。
javascript
function deepClone(obj) {
return JSON.parse(JSON.stringify(obj));
}
function filterTree(data, filterIds) {
const clonedData = deepClone(data);
return clonedData.filter(node => {
if (filterIds.includes(node.id)) {
return false;
}
if (node.children && node.children.length > 0) {
node.children = filterTree(node.children, filterIds);
}
return true;
});
}
const treeData = [
{ id: 1, name: '节点1', children: [{ id: 11, name: '节点1-1' }] },
{ id: 2, name: '节点2', children: [{ id: 21, name: '节点2-1' }] },
{ id: 3, name: '节点3' }
];
const filterIds = [2, 11];
const filteredTree = filterTree(treeData, filterIds);
console.log(JSON.stringify(filteredTree, null, 2));
console.log('原始数据未改变:', JSON.stringify(treeData, null, 2));
优点:
- 原数据保持不变,适合需要保留原始数据的场景。
方法 3:Vue 3 响应式数据处理
如果在 Vue 3 中使用(如 ref
或 reactive
),需要确保响应式数据正确更新。
vue
<template>
<el-tree :data="filteredTreeData" :props="treeProps" node-key="id" />
</template>
<script setup>
import { ref, onMounted } from 'vue';
// 树形数据
const treeData = ref([
{ id: 1, name: '节点1', children: [{ id: 11, name: '节点1-1' }] },
{ id: 2, name: '节点2', children: [{ id: 21, name: '节点2-1' }] },
{ id: 3, name: '节点3' }
]);
// 过滤后的数据
const filteredTreeData = ref([]);
// 树节点配置
const treeProps = {
label: 'name',
children: 'children'
};
// 需要过滤的 id
const filterIds = [2, 11];
// 过滤函数
function filterTree(data, filterIds) {
return data.filter(node => {
if (filterIds.includes(node.id)) {
return false;
}
if (node.children && node.children.length > 0) {
node.children = filterTree(node.children, filterIds);
}
return true;
});
}
// 初始化时过滤数据
onMounted(() => {
filteredTreeData.value = filterTree(treeData.value, filterIds);
});
</script>
说明:
- 使用
ref
管理树形数据,确保过滤后赋值给filteredTreeData
。 el-tree
使用过滤后的数据渲染。
方法 4:处理空 children 数组(可选优化)
在上述方法中,过滤后可能出现 children: []
的空数组。如果不需要保留空数组,可以在递归时清理。
javascript
function filterTree(data, filterIds) {
return data
.filter(node => !filterIds.includes(node.id))
.map(node => {
if (node.children && node.children.length > 0) {
node.children = filterTree(node.children, filterIds);
// 如果子节点过滤后为空,删除 children 属性
if (node.children.length === 0) {
delete node.children;
}
}
return node;
});
}
const treeData = [
{ id: 1, name: '节点1', children: [{ id: 11, name: '节点1-1' }] },
{ id: 2, name: '节点2', children: [{ id: 21, name: '节点2-1' }] },
{ id: 3, name: '节点3' }
];
const filterIds = [2, 11];
const filteredTree = filterTree(treeData, filterIds);
console.log(JSON.stringify(filteredTree, null, 2));
输出结果:
json
[
{
"id": 1,
"name": "节点1"
},
{
"id": 3,
"name": "节点3"
}
]
优点:
- 移除空
children
,数据更简洁。
注意事项
-
数据结构一致性:
- 确保树形数据中每个节点都有
id
和children
(即使为空数组)。 - 如果字段名不同(如子节点字段不是
children
),需调整代码中的字段名。
- 确保树形数据中每个节点都有
-
性能考虑:
- 对于大规模树形数据,递归可能有性能开销,但通常中小型数据无明显影响。
-
动态过滤:
- 如果
filterIds
是动态变化的(例如用户选择),可以在 Vue 中将其设为响应式变量,并在变化时重新调用filterTree
。
- 如果
总结
- 推荐方法:方法 1(递归过滤)简单直接,适用于大多数场景。
- Vue 3 场景 :使用方法 3,结合
ref
或reactive
。 - 数据清洁 :方法 4 可移除空
children
,适合需要精简输出的情况。