过滤tree数据中某些数据

在处理树形数据时,如果需要过滤掉 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,数据更简洁。

注意事项

  1. 数据结构一致性:

    • 确保树形数据中每个节点都有 id 和 children(即使为空数组)。
    • 如果字段名不同(如子节点字段不是 children),需调整代码中的字段名。
  2. 性能考虑:

    • 对于大规模树形数据,递归可能有性能开销,但通常中小型数据无明显影响。
  3. 动态过滤:

    • 如果 filterIds 是动态变化的(例如用户选择),可以在 Vue 中将其设为响应式变量,并在变化时重新调用 filterTree。

总结

  • 推荐方法:方法 1(递归过滤)简单直接,适用于大多数场景。
  • Vue 3 场景 :使用方法 3,结合 ref 或 reactive。
  • 数据清洁 :方法 4 可移除空 children,适合需要精简输出的情况。
相关推荐
丨白色风车丨3 分钟前
LangChain Agent 从入门到实战:创建与调用参数全解析
前端·python·langchain
Jmyd01238 小时前
Web端3D营销展厅技术实现路径:从素材上云到线索回流的数据链路
前端·3d·性能优化·三维数字化
半个落月8 小时前
LangChain Agent 中间件实战(上):生命周期、状态、短路与工具包
javascript·langchain
砚凝霜8 小时前
【软考信息安全】第二十二章 Web服务器安全分析与增强——Apache与IIS
服务器·前端·安全
半个落月8 小时前
LangChain Agent 中间件实战(下):DeepAgents文件权限、长期记忆与对话摘要
javascript·langchain
u01110267510 小时前
JPG、PNG、WebP 怎么选?按透明度、体积和使用场景做判断
前端·javascript·vue.js·图像处理·ai作画
jerrywus10 小时前
让 AI 写完代码后交一份报告:我改造了 answer-me-with-html
前端·claude·cursor
派小心.11 小时前
小程序分享链路中来源参数的传递校验
大数据·前端·数据库·人工智能·小程序·数据分析
hhb_61811 小时前
一键生成数据看板,ECharts实战演示
前端·javascript·echarts
Java后端的Ai之路11 小时前
08_React组件API
前端·react.js·前端框架