el-tree多个树进行节点同步联动(完整版)

2024.1.11今天我学习了如何对多个el-tree树进行相同节点的联动效果,如图:

这边有两棵树,我们发现第一个树和第二个树之间会有重复的指标,当我们选中第一个树的指标,我们希望第二个树如果也有重复的指标也能进行勾选上,反之也是。

一、难点:

(1)要让父节点变成半选状态

这个组件比较复杂的地方是要通过选中的子节点,拿到另外一个树对应的父节点,直接通过getHalfCheckedKeys是不行的,因为你当前不是在另外一个树做操作,获取不到当前的父节点,所以只能通过递归子节点,拿到对应的父节点。

(2)要拿到选中的所有子节点数据

setCheckedKeys(data,check)的data是拿到当前选中的子节点数据,如果当前子节点数据含有children数据,我们也需要通过递归的方法拿到所有的子节点数据。

二、重点方法:

setCheckedKeys(data,check)//data为当前选中节点的数据   check为所有选中节点的数据

三、关键步骤如下:

(1)第一个树选中的节点数据赋值给第二个树回显。

(2)第二个树选中的节点拼接第一个树选中的节点并过滤第二个树去掉的节点。

:highlight-current="true"高亮显示节点点击

四、完整代码如下:

<template>
  <div>
    <el-tree
        style="height: 30vh;overflow-y: scroll"
        node-key="id"
        ref="tree1"
        :default-expand-all="true"
        :props="defaultProps"
        :data="tree_demo1"
        @check="tree_check1"
        show-checkbox
    >
      <span slot-scope="{ node, data }">【{{ data.id }}】{{ data.label }}</span>
    </el-tree>
    <hr/>
    <el-tree
        :highlight-current="true"
        node-key="id"
        ref="tree2"
        style="height: 30vh;overflow-y: scroll"
        :default-expand-all="true"
        :props="defaultProps"
        :data="tree_demo2"
        @check="tree_check2"
        show-checkbox
    >
      <span slot-scope="{ node, data }">【{{ data.id }}】{{ data.label }}</span>
    </el-tree>
  </div>
</template>
<script>
export default {
  data() {
    return {
      tree_demo1: [],
      tree_demo2: [],
      default_data: [],
      defaultProps: {
        label: 'label',
        children: 'children'
      }
    }
  },
  created() {
    this.getList()
  },
  methods: {
    getList() {
      let demo = [
        {
          "children": [
            {
              "children": [
                {
                  "id": "001",
                  "label": "指标一",
                  "parent_id": 100,
                },
                {
                  "id": "002",
                  "label": "指标二",
                  "parent_id": 100,
                },
                {
                  "id": "003",
                  "label": "指标三",
                  "parent_id": 100,
                },
                {
                  "id": "004",
                  "label": "指标四",
                  "parent_id": 100,
                },
                {
                  "id": "005",
                  "label": "指标五",
                  "parent_id": 100,
                },
                {
                  "id": "006",
                  "label": "指标六",
                  "parent_id": 100,
                },
                {
                  "id": "007",
                  "label": "指标七",
                  "parent_id": 100,
                },
                {
                  "id": "008",
                  "label": "指标八",
                  "parent_id": 100,
                },
                {
                  "id": "009",
                  "label": "指标九",
                  "parent_id": 100,
                },
                {
                  "id": "010",
                  "label": "指标十",
                  "parent_id": 100,
                },
                {
                  "id": "011",
                  "label": "指标十一",
                  "parent_id": 100,
                },
                {
                  "id": "012",
                  "label": "指标十二",
                  "parent_id": 100,
                },
                {
                  "id": "013",
                  "label": "指标十三",
                  "parent_id": 100,
                },
                {
                  "id": "014",
                  "label": "指标十四",
                  "parent_id": 100,
                },
                {
                  "id": "015",
                  "label": "指标十五",
                  "parent_id": 100,
                },
                {
                  "id": "016",
                  "label": "指标十六",
                  "parent_id": 100,
                },
                {
                  "id": "017",
                  "label": "指标十七",
                  "parent_id": 100,
                },
                {
                  "id": "018",
                  "label": "指标十八",
                  "parent_id": 100,
                },
                {
                  "id": "019",
                  "label": "指标十九",
                  "parent_id": 100,
                },
                {
                  "id": "020",
                  "label": "指标二十",
                  "parent_id": 100,
                },
                {
                  "id": "021",
                  "label": "指标二十一",
                  "parent_id": 100,
                },
                {
                  "id": "022",
                  "label": "指标二十二",
                  "parent_id": 100,
                },
                {
                  "id": "023",
                  "label": "指标二十三",
                  "parent_id": 100,
                },
                {
                  "id": "024",
                  "label": "指标二十四",
                  "parent_id": 100,
                },
                {
                  "id": "025",
                  "label": "指标二十五",
                  "parent_id": 100,
                }
              ],
              "id": "100",
              "label": "指标分类1-1",
              "parent_id": 1,
            },
            {
              "children": [
                {
                  "id": "026",
                  "label": "指标二十六",
                  "parent_id": 101,
                },
                {
                  "id": "027",
                  "label": "指标二十七",
                  "parent_id": 101,
                },
                {
                  "id": "028",
                  "label": "指标二十八",
                  "parent_id": 101,
                },
                {
                  "id": "029",
                  "label": "指标二十九",
                  "parent_id": 101,
                },
                {
                  "id": "030",
                  "label": "指标三十",
                  "parent_id": 101,
                },
                {
                  "id": "031",
                  "label": "指标三十一",
                  "parent_id": 101,
                },
                {
                  "id": "032",
                  "label": "指标三十二",
                  "parent_id": 101,
                },
                {
                  "id": "033",
                  "label": "指标三十三",
                  "parent_id": 101,
                },
                {
                  "id": "034",
                  "label": "指标三十四",
                  "parent_id": 101,
                },
                {
                  "id": "035",
                  "label": "指标三十五",
                  "parent_id": 101,
                },
                {
                  "id": "036",
                  "label": "指标三十六",
                  "parent_id": 101,
                },
                {
                  "id": "037",
                  "label": "指标三十七",
                  "parent_id": 101,
                },
                {
                  "id": "038",
                  "label": "指标三十八",
                  "parent_id": 101,
                },
                {
                  "id": "039",
                  "label": "指标三十九",
                  "parent_id": 101,
                },
                {
                  "id": "040",
                  "label": "指标四十",
                  "parent_id": 101,
                }
              ],
              "id": "101",
              "label": "指标分类1-2",
              "parent_id": 1,
            },
          ],
          "id": "1",
          "label": "指标分类一",
          "parent_id": 0,
          "status": 1
        },
        {
          "children": [
            {
              "id": "005",
              "label": "指标五"
            },
            {
              "id": "010",
              "label": "指标十"
            },
            {
              "id": "011",
              "label": "指标十一"
            },
            {
              "id": "016",
              "label": "指标十六"
            },
            {
              "id": "020",
              "label": "指标二十"
            },
            {
              "id": "030",
              "label": "指标三十"
            },
            {
              "id": "034",
              "label": "指标三十四"
            },
            {
              "id": "033",
              "label": "指标三十三"
            },
            {
              "id": "031",
              "label": "指标三十一"
            },
            {
              "id": "021",
              "label": "指标二十一"
            },
            {
              "id": "050",
              "label": "指标五十"
            },
            {
              "id": "060",
              "label": "指标六十"
            },
            {
              "id": "066",
              "label": "指标六十六"
            },
            {
              "id": "068",
              "label": "指标六十八"
            },
            {
              "id": "070",
              "label": "指标七十"
            },
          ],
          "id": "2",
          "label": "指标分类二"
        }
      ]
      this.tree_demo1 = [demo[0]]//第一棵树数据
      this.tree_demo2 = [demo[1]]//第二棵树数据
    },
    // 第一棵树选中节点数据
    tree_check1(data, check) {
      this.component_check_data_method(data, check, 'tree2', 'tree_demo2')
    },
    // 第二棵树选中节点数据
    tree_check2(data, check) {
      this.component_check_data_method(data, check, 'tree1', 'tree_demo1')
    },
    //递归拿到选中所有的子节点数据
    findChildrenIds(data) {
      let all_ids = [data.id]
      if (data.children && data.children.length > 0) {
        for (let child of data.children) {
          all_ids = all_ids.concat(this.findChildrenIds(child));//判断是否含有children数据,如果有就递归继续拼接
        }
      }
      return all_ids
    },
    // 递归拿到对应所有的父节点数据
    findParentIds(id, data) {
      const parentIds = [];
      function findNode(node, parentId) {
        if (node.id === id) {
          parentIds.push(parentId);
          return true;
        }
        if (node.children) {
          for (const child of node.children) {
            if (findNode(child, node.id)) {
              parentIds.push(parentId);
              return true;
            }
          }
        }
        return false;
      }
      for (const node of data) {
        if (findNode(node, null)) {
          break;
        }
      }
      return parentIds.reverse(); // 反转数组,让根节点id在最前面
    },
    // 通用选中节点获取数据的方法
    component_check_data_method(data, check, other_tree_ref, other_tree_data) {
      let first_data = this.$refs[other_tree_ref].getCheckedKeys()//获取另外一棵树的节点数据
      let all_nodes = []
      for (const nodeId of this.findChildrenIds(data)) {
        const parentIds = this.findParentIds(nodeId, this[other_tree_data])
        all_nodes.push(...parentIds)//拿到当前子节点对应的所有父节点
      }
      const filteredArr = [...new Set(all_nodes.filter(item => item !== null))]//去重和过滤null
      let select_all_data = [...filteredArr, ...this.findChildrenIds(data)]//拼接所有父节点和所有选中的子节点
      first_data = first_data.filter(item => !select_all_data.includes(item));//如果包含当前子节点就过滤
      this.$refs[other_tree_ref].setCheckedKeys([...first_data, ...check.checkedKeys])
    }
  }
}
</script>

可以直接复制demo查看效果。大家如果有不懂的地方或是更好的方法可以分享到评论区,谢谢!

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
对于el-tree展开节点后是另一个el-tree的情况,你可以通过使用el-tree组件的自定义模板来实现。在展开节点时,你可以将子节点绑定到另一个el-tree组件的数据源中。 首先,确保你已经在项目中引入了el-tree组件。然后,在你的Vue组件中,可以这样定义el-tree组件: ```html <template> <div> <el-tree :data="treeData" :node-key="nodeKey" :props="defaultProps" @node-click="handleNodeClick"></el-tree> </div> </template> <script> export default { data() { return { treeData: [ { label: '节点1', children: [ { label: '子节点1', children: [ { label: '子节点1.1', }, { label: '子节点1.2', }, ], }, ], }, { label: '节点2', children: [ { label: '子节点2', children: [ { label: '子节点2.1', }, { label: '子节点2.2', }, ], }, ], }, ], nodeKey: 'label', defaultProps: { children: 'children', label: 'label', }, }; }, methods: { handleNodeClick(data) { // 在这里处理节点点击事件 // 获取点击的节点数据data,然后将其作为新的数据源赋值给另一个el-tree组件 this.treeData = data.children; }, }, }; </script> ``` 在上面的示例中,我们使用了el-tree组件的data属性绑定了的数据源。当点击节点时,通过handleNodeClick方法获取到该节点的子节点数据,然后将其赋值给treeData,这样就实现了展开节点后显示另一个el-tree的效果。 注意,你可以根据实际需求修改数据结构和事件处理逻辑。这只是一个简单的示例,希望能对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

敲代码无敌小奶龙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值