过滤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 中使用(如 refreactive),需要确保响应式数据正确更新。

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. 数据结构一致性

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

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

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

总结

  • 推荐方法:方法 1(递归过滤)简单直接,适用于大多数场景。
  • Vue 3 场景 :使用方法 3,结合 refreactive
  • 数据清洁 :方法 4 可移除空 children,适合需要精简输出的情况。
相关推荐
BillKu28 分钟前
Vue3 + Element-Plus 抽屉关闭按钮居中
前端·javascript·vue.js
DevilSeagull31 分钟前
JavaScript WebAPI 指南
java·开发语言·javascript·html·ecmascript·html5
面向星辰1 小时前
html中css的四种定位方式
前端·css·html
Async Cipher1 小时前
CSS 权重(优先级规则)
前端·css
大怪v1 小时前
前端佬:机器学习?我也会啊!😎😎😎手“摸”手教你做个”自动驾驶“~
前端·javascript·机器学习
Liquad Li2 小时前
Angular 面试题及详细答案
前端·angular·angular.js
用户21411832636022 小时前
首发!即梦 4.0 接口开发全攻略:AI 辅助零代码实现,开源 + Docker 部署,小白也能上手
前端
gnip4 小时前
链式调用和延迟执行
前端·javascript
SoaringHeart4 小时前
Flutter组件封装:页面点击事件拦截
前端·flutter
杨天天.4 小时前
小程序原生实现音频播放器,下一首上一首切换,拖动进度条等功能
前端·javascript·小程序·音视频