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

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

一、开发前需要知道的

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java版电子招投标采购|投标|评标|竞标|邀标|评审招投标系统源码

招投标管理系统是一款适用于招标代理、政府采购、企业采购和工程交易等领域的企业级应用平台。该平台以项目为主线&#xff0c;从项目立项到项目归档&#xff0c;实现了全流程的高效沟通和协作。通过该平台&#xff0c;用户可以实时共享项目数据信息&#xff0c;实现规范化管理…

【Verilog HDL 入门教程】 —— 学长带你学Verilog(基础篇)

文章目录 一、Verilog HDL 概述1、Verilog HDL 是什么2、Verilog HDL产生的背景3、Verilog HDL 和 VHDL的区别 二、Verilog HDL 基础知识1、Verilog HDL 语言要素1.1、命名规则1.2、注释符1.3、关键字1.4、数值1.4.1、整数及其表示1.4.2、实数及其表示1.4.3、字符串及其表示 2、…

龙迅#LT7911E适用于EDP/DP/TPYE-C转MIPIDSI应用,支持图像处理功能,内置I2C,主应用副屏显示,投屏领域!

1. 描述 LT7911E 是一款高性能 eDP 转 MIPI D-PHY 转换器&#xff0c;旨在将 eDP 源连接到 MIPI 显示面板。 LT7911E 集成了一个符合 eDP1.4 标准的接收器&#xff0c;支持 1.62Gbps 至 5.67Gbps 的输入数据&#xff0c;以 270Mbps 的递增步长&#xff0c;以及一个 2 端口 D…

《算法SM9》题目

判断题 SM9密码算法系统参数由KGC选择。 A.正确 B.错误 正确答案A 多项选择题 SM9密码算法KGC是负责&#xff08; &#xff09;的可信机构。 A.选择系统参数 B.生成主密钥 C.生成用户标识 D.生成用户私钥 正确答案ABD 判断题 SM9密钥封装机制封装的秘密密钥是根据…

C语言——实现求出最大值

问题描述&#xff1a;利用C语言自定义函数求出一维数组里边最大的数字 //利用函数找最大数#include<stdio.h>int search(int s[9]) //查找函数 {int i , max s[0] , max_xia 0;for(i0;i<9;i){if(s[i] > max){max_xia i;max s[max_xia];}}return max; } in…

【尚硅谷 - SSM+SpringBoot+SpringSecurity框架整合项目 】项目打包并且本地部署

前后端分离开发&#xff1a;把一个项目拆成两部分进行开发&#xff0c;所以在打包的时候&#xff0c;需要使用不同的打包方式。 后端 – SpringBoot – jar包 前端 – Vue: 因为使用了vue-admin-template框架&#xff1a;所以先使用框架进行打包使用Nginx部署&#xff0c;通…

【SH】Ubuntu Server 24服务器搭建MySQL数据库研发笔记

文章目录 搭建服务器在线安装1. 更新软件包列表2. 安装MySQL3. 检查MySQL状态4. 修改密码5. 新增用户6. 设置局域网访问 离线安装下载安装包 常用命令参考文档在线安装日志 搭建服务器 作者羊大侠搭建的是 Ubuntu Server 24.04 LTS 服务器环境 搭建参考文档&#xff1a;【SH】…

容器化技术全面解析:Docker 与 Containerd 的深入解读

目录 Docker 简介 1. 什么是 Docker&#xff1f; 2. Docker 的核心组件 3. Docker 的主要功能 4. Docker 的优点 5. Docker 的使用场景 Containerd 简介 1. 什么是 Containerd&#xff1f; 2. Containerd 的核心特性 3. Containerd 的架构 4. Containerd 与 Docker 的…

华为数通最新题库 H12-821 HCIP稳定过人中

以下是成绩单和考试人员 HCIP H12-831 HCIP H12-725 安全中级

Webots控制器编程

本文主要内容是如何编写Webots控制器&#xff0c;使用语言为Python。 文章目录 1. 新增控制器2. Hello World Example3. 读取传感器4. 使用执行器5. 理解step和robot.step函数6. 同时使用传感器和执行器7. 控制器参数 1. 新增控制器 对机器人Robot新增控制器的方式&#x…

[SAP ABAP] 将内表数据转换为HTML格式

从sflight数据库表中检索航班信息&#xff0c;并将这些信息转换成HTML格式&#xff0c;然后下载或显示在前端 开发步骤 ① 自定义一个数据类型 ty_sflight 来存储航班信息 ② 声明内表和工作区变量&#xff0c;用于存储表头、字段、HTML内容和航班详细信息以及创建字段目录lt…

《算法SM4》题目

单项选择题 我国商用密码算法SM4迭代结构是&#xff08;&#xff09;。 A.平衡Fesitel网络结构 B.非平衡Fesitel网络结构 C.SP结构 D.MD结构 正确答案B 多项选择题 SM4分组密码算法轮函数中的T置换&#xff0c;包括的运算有&#xff08;&#xff09;。 A.非线性变换 …

深度学习革新音乐转录

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

Flink2.0未来趋势中需要注意的一些问题

手机打字&#xff0c;篇幅不长&#xff0c;主要讲一下FFA中关于Flink2.0的未来趋势&#xff0c;直接看重点。 Flink Forward Asia 2024主会场有一场关于Flink2.0的演讲&#xff0c;很精彩&#xff0c;官方也发布了一些关于Flink2.0的展望和要解决的问题。 1.0时代和2.0时代避免…

EasyPlayer.js播放器Web播放H.265要兼顾哪些方面?

在数字化时代&#xff0c;流媒体技术已经成为信息传播和娱乐消费的重要方式。随着互联网技术的飞速发展和移动设备的普及&#xff0c;流媒体服务正在重塑我们的生活和工作方式。从视频点播、在线直播到音乐流媒体&#xff0c;流媒体技术的广泛应用不仅改变了内容的分发和消费模…

在 Solana 上实现 SOL 转账及构建支付分配器

与以太坊不同&#xff0c;在以太坊中&#xff0c;钱包通过 msg.value 指定交易的一部分并“推送” ETH 到合约&#xff0c;而 Solana 程序则是从钱包“拉取” Solana。 因此&#xff0c;没有“可支付”函数或“msg.value”这样的概念。 下面我们创建了一个新的 anchor 项目&a…

灵活接入第三方接口,解析第三方json数据,返回我们想要的json格式

需求&#xff1a;我想接入任意第三方http 接口&#xff08;暂不考虑鉴权问题&#xff09;、接口返回任意json数据。 1、要求返回的json数据通过我的R< T > 返回。 2、我的R< T > 里面包含参数 data&#xff0c;code&#xff0c;msg&#xff0c;success标识。 3、…

ExcelVBA编程输出ColorIndex与对应颜色色谱

标题 ExcelVBA编程输出ColorIndex与对应颜色色谱 正文 解决问题编程输出ColorIndex与对应色谱共56&#xff0c;打算分4纵列输出&#xff0c;标题是ColorIndex,Color,Name 1. 解释VBA中的ColorIndex属性 在VBA&#xff08;Visual Basic for Applications&#xff09;中&#xff…

【常微分方程讲义1.1】方程的种类发展与完备

方程在数学历史中不断发展&#xff0c;逐步趋于完备。从最初的简单代数方程到包含函数、算子甚至泛函的更复杂方程&#xff0c;数学家通过不断的扩展和深化&#xff0c;逐渐建立起更为丰富和多元的方程类型体系。方程的种类之所以不断演变&#xff0c;部分是因为解决实际问题的…

Unity 组件学习记录:Aspect Ratio Fitter

概述 Aspect Ratio Fitter是 Unity 中的一个组件&#xff0c;用于控制 UI 元素&#xff08;如Image、RawImage等&#xff09;的宽高比。它在处理不同屏幕分辨率和尺寸时非常有用&#xff0c;可以确保 UI 元素按照预期的比例进行显示。当添加到一个 UI 对象上时&#xff0c;Aspe…