Element@2.15.14-tree checkStrictly 状态实现父项联动子项,实现节点自定义编辑、新增、删除功能

news2024/12/19 16:42:11

背景:现在有一个新需求,需要借助树结构来实现词库的分类管理,树的节点是不同的分类,不同的分类可以有自己的词库,所以父子节点是互不影响的;同样为了选择的方便性,提出了新需求,选择了父级子级需要全选,父级取消勾选子级需要全部取消勾选;分类支持修改名称、增加子节点、删除子节点,多选子节点时需要获取当前所选分类下的所有词库。

一、开发前需要知道的

1、树结构需要借助 element 的 tree 组件

2、树结构需要设置父子级不关联,即 :check-strictly="true"

3、节点选择时如果是非叶子结点(最后一层的子节点,没有 children),需要递归获取子节点,如果进行节点的选择与取消选择

4、自定义节点需要通过 slot 方式活着 render-content 方式实现

二、实现流程

1、引入 tree,传入源数据 data、设置 key,设置默认配置属性 defaultProps

1. 定义 tree
<el-tree
    :check-strictly="true"
    :data="data"
    @check-change="checkChange"
    ref="treeRef"
    show-checkbox
    default-expand-all
    node-key="id"
    ref="tree"
    highlight-current
    :props="defaultProps"
>
</el-tree>
2. 设置 data
data = [{id: xx, label: xx, children: {id: number, label: string, children: []}[]}]
3. 设置父子不关联
:check-strictly="true"
4. 设置默认配置
const defaultProps = {
    children: "children",
    label: "label",
}

2、实现父子勾选子级联动

// 1. 给 el-tree 绑定 check-change 事情
@check-change="checkChange"

// 2. 实现 checkChange 函数
// data:当前节点 checked:节点是否选中 indeterminate:是否有选中的子项
function checkChange(data, checked, indeterminate) {
    console.log("data, checked, indeterminate", data, checked, indeterminate);
    this.$nextTick(() => {
        // 2.1 获取节点详细信息
        const nodeInfo = this.$refs.treeRef.getNode(data.id);
        const { isLeaf, checked } = nodeInfo;
        this.nodeInfo = nodeInfo;
        function getAllIds(arr, res = []) {
            for (let i = 0; i < arr.length; i++) {
                res.push(arr[i].id);
                if (arr[i].children && arr[i].children.length) {
                    getAllIds(arr[i].children, res);
                }
            }
            return res;
        }
        // 2.2 获取当前已选中的节点
        console.log(this.$refs.treeRef.getCheckedKeys());
        // 2.3 如果是父级,子级选中跟取消选择
        if (!isLeaf) {
        const checkedIds = this.$refs.treeRef.getCheckedKeys();
        const ids = getAllIds(nodeInfo.data.children);
        console.log(ids);
        // 2.3.1 父级选中,子级全选
        if (checked) {
            this.$refs.treeRef.setCheckedKeys(
            Array.from(new Set([...checkedIds, ...ids]))
            );
        } else {
        // 2.3.2 父级取消选中,子级全不选
            this.$refs.treeRef.setCheckedKeys(
                Array.from(new Set(checkedIds.filter((item) => !ids.includes(item))))
            );
        }
        }
    });
},

3、通过 slot 实现编辑、新增、删除

1. slot 内容
<span class="custom-tree-node" slot-scope="{ node, data }">
    <span>{{ node.label }}</span>
    <span>
    <el-button type="text" size="mini" @click="() => edit(node, data)">
        edit
    </el-button>
    <el-button type="text" size="mini" @click="() => append(data)">
        Append
    </el-button>
    <el-button
        type="text"
        size="mini"
        @click="() => remove(node, data)"
    >
        Delete
    </el-button>
    </span>
</span>

2. 设置函数
{
  // 2.1 编辑,子级可以弹窗回显名称,然后修改名称
  edit(node, data) {
    console.log(node, data);
  },
  // 2.2 新增,新增内容自己定,也可以弹窗自定义名称,通过接口返回 id 再拼接
  append(data) {
    const newChild = { id: this.id++, label: "testtest", children: [] };
    if (!data.children) {
      this.$set(data, "children", []);
    }
    data.children.push(newChild);
  },
  // 2.3 删除,可以先进行提示,提示确定后再删
  remove(node, data) {
    const parent = node.parent;
    const children = parent.data.children || parent.data;
    const index = children.findIndex((d) => d.id === data.id);
    children.splice(index, 1);
  }
}

三、整体代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link
      rel="stylesheet"
      href="https://unpkg.com/element-ui@2.15.14/lib/theme-chalk/index.css"
    />
    <style>
      .custom-tree-node {
        flex: 1;
        display: flex;
        align-items: center;
        justify-content: space-between;
        font-size: 14px;
        padding-right: 8px;
      }
    </style>
  </head>
  <body>
    <script src="https://unpkg.com/vue@2.7.16/dist/vue.js"></script>
    <script src="https://unpkg.com/element-ui@2.15.14/lib/index.js"></script>
    <div id="app">
      <el-tree
        :check-strictly="true"
        :data="data"
        @check-change="checkChange"
        ref="treeRef"
        show-checkbox
        default-expand-all
        node-key="id"
        ref="tree"
        highlight-current
        :props="defaultProps"
      >
        <span class="custom-tree-node" slot-scope="{ node, data }">
          <span>{{ node.label }}</span>
          <span>
            <el-button type="text" size="mini" @click="() => edit(node, data)">
              edit
            </el-button>
            <el-button type="text" size="mini" @click="() => append(data)">
              Append
            </el-button>
            <el-button
              type="text"
              size="mini"
              @click="() => remove(node, data)"
            >
              Delete
            </el-button>
          </span>
        </span>
      </el-tree>
      <div class="buttons">
        <el-button @click="getCheckedNodes">通过 node 获取</el-button>
        <el-button @click="getCheckedKeys">通过 key 获取</el-button>
        <el-button @click="setCheckedNodes">通过 node 设置</el-button>
        <el-button @click="setCheckedKeys">通过 key 设置</el-button>
        <el-button @click="resetChecked">清空</el-button>
      </div>
    </div>
    <script>
      var Main = {
        methods: {
          edit(node, data) {
            console.log(node, data);
          },
          append(data) {
            const newChild = { id: this.id++, label: "testtest", children: [] };
            if (!data.children) {
              this.$set(data, "children", []);
            }
            data.children.push(newChild);
          },
          remove(node, data) {
            const parent = node.parent;
            const children = parent.data.children || parent.data;
            const index = children.findIndex((d) => d.id === data.id);
            children.splice(index, 1);
          },
          checkChange(data, checked, indeterminate) {
            this.node = data;
            this.checked = checked;
            this.indeterminate = indeterminate;
            // console.log("data, checked, indeterminate", data, checked, indeterminate);
            this.$nextTick(() => {
              console.log(data.id);
              const nodeInfo = this.$refs.treeRef.getNode(data.id);
              const { isLeaf, checked } = nodeInfo;
              this.nodeInfo = nodeInfo;
              console.log(nodeInfo);
              // console.log(
              //   "nodeInfo, isLeaf, childNodes, checked",
              //   nodeInfo,
              //   isLeaf,
              //   childNodes,
              //   checked
              // );
              function getAllIds(arr, res = []) {
                for (let i = 0; i < arr.length; i++) {
                  res.push(arr[i].id);
                  if (arr[i].children && arr[i].children.length) {
                    getAllIds(arr[i].children, res);
                  }
                }
                return res;
              }
              console.log(this.$refs.treeRef.getCheckedKeys());
              if (!isLeaf) {
                const checkedIds = this.$refs.treeRef.getCheckedKeys();
                const ids = getAllIds(nodeInfo.data.children);
                console.log(ids);
                if (checked) {
                  this.$refs.treeRef.setCheckedKeys(
                    Array.from(new Set([...checkedIds, ...ids]))
                  );
                } else {
                  this.$refs.treeRef.setCheckedKeys(
                    Array.from(
                      new Set(checkedIds.filter((item) => !ids.includes(item)))
                    )
                  );
                }
              }
            });
          },
          getCheckedNodes() {
            console.log(this.$refs.tree.getCheckedNodes());
          },
          getCheckedKeys() {
            console.log(this.$refs.tree.getCheckedKeys());
          },
          setCheckedNodes() {
            this.$refs.tree.setCheckedNodes([
              {
                id: 5,
                label: "二级 2-1",
              },
              {
                id: 9,
                label: "三级 1-1-1",
              },
            ]);
          },
          setCheckedKeys() {
            this.$refs.tree.setCheckedKeys([3]);
          },
          resetChecked() {
            this.$refs.tree.setCheckedKeys([]);
          },
        },

        data() {
          return {
            id: 10,
            data: [
              {
                id: 1,
                label: "一级 1",
                children: [
                  {
                    id: 4,
                    label: "二级 1-1",
                    children: [
                      {
                        id: 9,
                        label: "三级 1-1-1",
                      },
                      {
                        id: 10,
                        label: "三级 1-1-2",
                      },
                    ],
                  },
                ],
              },
              {
                id: 2,
                label: "一级 2",
                children: [
                  {
                    id: 5,
                    label: "二级 2-1",
                  },
                  {
                    id: 6,
                    label: "二级 2-2",
                  },
                ],
              },
              {
                id: 3,
                label: "一级 3",
                children: [
                  {
                    id: 7,
                    label: "二级 3-1",
                  },
                  {
                    id: 8,
                    label: "二级 3-2",
                  },
                ],
              },
            ],
            defaultProps: {
              children: "children",
              label: "label",
            },
          };
        },
      };
      var Ctor = Vue.extend(Main);
      new Ctor().$mount("#app");
    </script>
  </body>
</html>

四、codepen 在线编辑

https://codepen.io/CAILeiz/pen/MYgpYOW

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2262264.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SAP-ABAP开发学习-面向对象开发ooalv(2)

SAP-ABAP开发学习-面向对象OOALV&#xff08;1&#xff09;-CSDN博客 本文目录 一、类的继承 多态性类继承的实现 二、抽象类 三、最终类 四、接口 五、定义全局对象 一、类的继承 继承的本质是代码重用。当我们要构造一个新类时&#xff0c;无需从零开始&#xff0c;可…

典型案例 | 旧PC新蜕变!东北师范大学依托麒麟信安云“旧物焕新生”

东北师范大学始建于1946年&#xff0c;坐落于吉林省长春市&#xff0c;是中国共产党在东北地区创建的第一所综合性大学。作为国家“双一流”建设高校&#xff0c;学校高度重视教学改革和科技创新&#xff0c;校园信息化建设工作始终走在前列。基于麒麟信安云&#xff0c;东北师…

Linux脚本语言学习--上

1.shell概述 1.1 shell是什么&#xff1f; Shell是一个命令行解释器&#xff0c;他为用户提供了一个向Linux内核发送请求以便运行程序的界面系统级程序&#xff0c;用户可以使用Shell来启动&#xff0c;挂起&#xff0c;停止甚至是编写一些程序。 Shell还是一个功能相当强大…

2024年底-Sre面试问题总结-持续更新

这几个缩写 贴一下是因为真的会有人问:( SRE “Site Reliability Engineer” 站点可靠性工程师 SLA “Service Level Agreement” 服务可用性协议 CICD “Continuos Integration Continous Deployment” 持续集成 持续部署 3个高频问题 K8s生产环境中处理过哪些复杂 or 印象…

【硬件接口】I2C总线接口

本文章是笔者整理的备忘笔记。希望在帮助自己温习避免遗忘的同时&#xff0c;也能帮助其他需要参考的朋友。如有谬误&#xff0c;欢迎大家进行指正。 一、概述 I2C总线是一种非常常用的总线&#xff0c;其多用于一个主机&#xff08;或多个&#xff09;与单个或多个从设备通讯…

OkHttp源码分析:分发器任务调配,拦截器责任链设计,连接池socket复用

目录 一&#xff0c;分发器和拦截器 二&#xff0c;分发器处理异步请求 1.分发器处理入口 2.分发器工作流程 3.分发器中的线程池设计 三&#xff0c;分发器处理同步请求 四&#xff0c;拦截器处理请求 1.责任链设计模式 2.拦截器工作原理 3.OkHttp五大拦截器 一&#…

SAP:如何修改已释放的请求

SAP:如何修改已释放的请求 QQ出了一个新功能&#xff0c;把10年前的旧日志推给自己。这个10年前的日志&#xff0c;是用户反映在SE10中把请求释放后发现漏了内容&#xff0c;想修改已释放的请求。经调查写了一个小程序&#xff0c;实现用户的需求。 *&-------------------…

python怎么循环嵌套

嵌套循环&#xff1a; 概念&#xff1a;循环中再定义循环&#xff0c;称为嵌套循环&#xff1b; 【注意】嵌套循环可能有多层&#xff0c;但是一般我们实际开发最多两层就可以搞定了(99%的情况) 格式&#xff1a; 1、while中套while常用 2、while中套for in 3、for in中套…

前端优雅(装逼)写法(updating····)

1.>>右位移运算符取整数 它将一个数字的二进制位向右移动指定的位数&#xff0c;并在左侧填充符号位&#xff08;即负数用1填充&#xff0c;正数用0填充&#xff09;。 比如 2.99934 >> 0&#xff1a;取整结果是2&#xff0c;此处取整并非四舍五入 2.99934 会先…

MySQL -- 库的相关操作

目录 查看数据库 创建数据库 直接创建&#xff1a; 加约束条件 if not exists 字符集和校对规则 什么是字符集 什么是校对规则 校对规则的主要功能 校对规则的特性 查看指定的数据库使用的字符集和校对规则&#xff1a; 比较是否区分大小写字母差异 显示创建语句 …

Moretl开箱即用日志采集

永久免费: 至Gitee下载 使用教程: Moretl使用说明 使用咨询: 用途 定时全量或增量采集工控机,电脑文件或日志. 优势 开箱即用: 解压直接运行.不需额外下载.管理设备: 后台统一管理客户端.无人值守: 客户端自启动,自更新.稳定安全: 架构简单,兼容性好,通过授权控制访问. 架…

分享一次接口性能摸底测试过程

接口性能测试是用于验证应用程序中的接口是否可以满足系统的性能要求的一种测试方法。确定应用程序在各种负载条件下的性能指标&#xff0c;例如响应时间、吞吐量、并发性能等&#xff0c;以便提高系统的性能和可靠性。本文主要讲述接口性能测试从前期准备、方案设计到环境搭建…

【机器学习】机器学习的基本分类-无监督学习-t-SNE(t-分布随机邻域嵌入)

t-SNE&#xff08;t-分布随机邻域嵌入&#xff09; t-SNE&#xff08;t-distributed Stochastic Neighbor Embedding&#xff09;是一种用于降维的非线性技术&#xff0c;常用于高维数据的可视化。它特别适合展示高维数据在二维或三维空间中的分布结构&#xff0c;同时能够很好…

【教学类-83-03】20241218立体书盘旋蛇3.0——圆点蛇1(蚊香形)

背景需求&#xff1a; 制作儿童简易立体书贺卡 【教学类-83-01】20241215立体书三角嘴1.0——小鸡&#xff08;正菱形嘴&#xff09;-CSDN博客文章浏览阅读1k次&#xff0c;点赞24次&#xff0c;收藏18次。【教学类-83-01】20241215立体书三角嘴1.0——小鸡&#xff08;正菱形…

监控视频汇聚融合云平台一站式解决视频资源管理痛点

随着5G技术的广泛应用&#xff0c;各领域都在通信技术加持下通过海量终端设备收集了大量视频、图像等物联网数据&#xff0c;并通过人工智能、大数据、视频监控等技术方式来让我们的世界更安全、更高效。然而&#xff0c;随着数字化建设和生产经营管理活动的长期开展&#xff0…

JAVA 零拷贝技术和主流中间件零拷贝技术应用

目录 介绍Java代码里面有哪些零拷贝技术java 中文件读写方式主要分为什么是FileChannelmmap实现sendfile实现 文件IO实战需求代码编写实战IOTest.java 文件上传阿里云&#xff0c;测试运行代码看耗时为啥带buffer的IO比普通IO性能高&#xff1f;BufferedInputStream为啥性能高点…

云灾备技术

目录 云灾备分类与定义 云容灾定义与主要应用场景 云容灾定义 应用场景 云备份定义与主要应用场景 云备份定义 应用场景 云容灾参考模型与关键技术 云备份参考模型与关键技术 云灾备分类与定义 云容灾技术是指保护云数据中心业务持续性的灾备技术&#xff0c;它是云灾…

进程通信方式---共享映射区(无血缘关系用的)

5.共享映射区&#xff08;无血缘关系用的&#xff09; 文章目录 5.共享映射区&#xff08;无血缘关系用的&#xff09;1.概述2.mmap&&munmap函数3.mmap注意事项4.mmap实现进程通信父子进程练习 无血缘关系 5.mmap匿名映射区 1.概述 原理&#xff1a;共享映射区是将文件…

leetcode 面试经典 150 题:长度最小的子数组

链接长度最小的子数组题序号209题型数组解题方法滑动窗口难度中等 题目 给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其总和大于等于 target 的长度最小的 子数组 [numsl, numsl1, …, numsr-1, numsr] &#xff0c;并返回其长度。如果不存在符合条件…

代码随想录day22 | 回溯算法理论基础 leetcode 77.组合 77.组合 加剪枝操作 216.组合总和III 17.电话号码的字母组合

DAY22 回溯算法开始 学到目前最烧脑的一天 回溯算法理论基础 任何回溯算法都可以抽象成一个树结构 理论基础 什么是回溯法 回溯法也可以叫做回溯搜索法&#xff0c;它是一种搜索的方式。 在二叉树系列中&#xff0c;我们已经不止一次&#xff0c;提到了回溯 回溯是递归的副…