el-table的树形结构结合多选框使用,实现单选父子联动,全选,反选功能

news2024/9/21 17:56:29

<template>
  <div>
    <el-table
      :data="tableData"
      :row-key="rowKey"
      :default-expand-all="defaultExpandAll"
      :tree-props="treeProps"
    >
      <!-- 开启树形多选 -->
      <el-table-column v-if="showSelection" width="120" align="left">
        <template #header>
          <el-checkbox
            v-model="selectAll"
            :checked="selectAll"
            :indeterminate="isIndeterminate"
            @change="setCheckAll"
          />
          {{ selectionName }}
        </template>

        <template #default="scope">
          <el-checkbox
            v-model="scope.row[selectionConfig.checked]"
            :checked="scope.row[selectionConfig.checked]"
            :indeterminate="scope.row[selectionConfig.indeterminate]"
            :disabled="scope.row[selectionConfig.disabled]"
            @change="setCheck(scope.row)"
          />
        </template>
      </el-table-column>
      <el-table-column prop="name" label="Name" width="180" />
    </el-table>
  </div>
</template>

<script>
export default {
  props: {
    // 表格树形数据
    // 列配置项
    columnConfig: {
      type: Array,
      default: () => [
        {
          prop: 'default',
          label: '默认',
          width: '200',
          align: 'center',
          ownDefinedFn: () => {
            return '默认' // 可返回函数
          }
        }
      ]
    },
    // 数据唯一标识
    rowKey: {
      type: String,
      default: 'id'
    },
    // 默认展开所有节点
    defaultExpandAll: {
      type: Boolean,
      default: true
    },
    // 渲染嵌套数据的配置选项
    treeProps: {
      type: Object,
      default: () => ({
        children: 'children'
      })
    },
    // 默认开启树形多选框
    showSelection: {
      type: Boolean,
      default: true
    },
    // 树形多选框标题
    selectionName: {
      type: String,
      default: ''
    },
    // 多选框配置
    selectionConfig: {
      type: Object,
      default: () => ({
        checked: 'checked',
        indeterminate: 'indeterminate',
        disabled: 'disabled'
      })
    }
  },
  data() {
    return {
      selectAll: false, // 全选
      isIndeterminate: false, // 半选
      tableData: [
        {
          id: '1',
          name: '目录1',
          parentId: '0',
          checked: false,
          isItemIndeterminate: false,
          children: [
            {
              id: '1-1-1-1',
              name: '目录1-1-1-1',
              parentId: '1',
              checked: false,
              isItemIndeterminate: false,
              children: []
            },
            {
              id: '1-1-1-2',
              name: '目录1-1-1-2',
              parentId: '1',
              checked: false,
              isItemIndeterminate: false,
              children: []
            }
          ]
        },
        { id: '2', name: '目录2', parentId: '0', checked: false, children: [] },
        { id: '3', name: '目录3', parentId: '0', checked: false, children: [] },
        { id: '4', name: '目录4', parentId: '0', checked: false, children: [] }
      ]
    }
  },
  methods: {
    // 全选
    setCheckAll() {
      console.log(this.selectAll)
      this.tableData.forEach((item) => {
        if (!item[this.selectionConfig.disabled]) {
          item[this.selectionConfig.checked] = this.selectAll
        }
        this.setChildren(item, this.selectAll)
      })
      this.isIndeterminate = false
    },
    // 单选
    setCheck(row) {
      // 设置该单元格所有子节点状态
      this.setChildren(row, row[this.selectionConfig.checked])
      let result = this.setParentCheck(row)
      // 遍历到顶级,顶级无父节点,判断顶级节点是否都为选中
      if (!result) {
        let isAll = this.tableData.every((item) => {
          return item[this.selectionConfig.checked]
        })
        this.selectAll = isAll

        if (isAll) {
          this.isIndeterminate = false
        } else {
          let isIndeterminate = this.tableData.some((item) => {
            return item[this.selectionConfig.checked] || item[this.selectionConfig.indeterminate]
          })
          this.isIndeterminate = isIndeterminate
        }
      }
    },
    // 设置子节点
    setChildren(row, checked) {
      row[this.selectionConfig.indeterminate] = false

      if (row[this.treeProps.children]) {
        row[this.treeProps.children].forEach((item) => {
          if (!item[this.selectionConfig.disabled]) {
            item[this.selectionConfig.checked] = checked
            item[this.selectionConfig.indeterminate] = false

          }
          if (row[this.treeProps.children]) {
            this.setChildren(item, checked)
          }
        })
      }
    },
    // 设置父节点
    setParentCheck(row) {
      // 寻找该行数据的父节点
      let parent = null
      for (let i = 0; i < this.tableData.length; i++) {
        parent = this.findItem(this.tableData[i], row.parentId)
        if (parent != null) {
          break
        }
      }
      // 遍历该行的父节点下,所有的子节点
      if (parent != null) {
        if (parent[this.treeProps.children]) {
          // 子节点是否全都选中,如果是则则勾选该节点
          let isAll = parent[this.treeProps.children].every((item) => {
            return item[this.selectionConfig.checked]
          })
          parent[this.selectionConfig.checked] = isAll
          if (isAll) {
            parent[this.selectionConfig.indeterminate] = false
          } else {
            let isIndeterminate = parent[this.treeProps.children].some((item) => {
              return item[this.selectionConfig.checked]
            })
            parent[this.selectionConfig.indeterminate] = isIndeterminate
          }

          // 递归查找该行父级的父级节点
          this.setParentCheck(parent, parent[this.selectionConfig.checked])
        }
      } else {
        // 遍历到顶级,停止
        return null
      }
    },
    // 查递归找该行的父节点
    findItem(row, id) {
      if (row.id == id) {
        return row
      }
      if (row[this.treeProps.children]) {
        let parent = null
        for (let i = 0; i < row[this.treeProps.children].length; i++) {
          parent = this.findItem(row[this.treeProps.children][i], id)
          if (parent) {
            break
          }
        }
        return parent
      } else {
        return null
      }
    }
  }
}
</script>

<style lang="less" scoped></style>

参考链接

https://blog.csdn.net/weixin_47342392/article/details/139168459

人工智能学习网站

https://chat.xutongbao.top

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

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

相关文章

无人机+自组网:中继通信增强技术详解

无人机与自组网技术的结合&#xff0c;特别是通过中继通信增强技术&#xff0c;为无人机在复杂环境中的通信提供了稳定、高效、可靠的解决方案。以下是对该技术的详细解析&#xff1a; 一、无人机自组网技术概述 无人机自组网技术是一种利用无人机作为节点&#xff0c;通过无…

【可测试性实践】C++单元测试:gtest gmock

引言 google test是目前C主流的单元测试框架&#xff0c;本文介绍如何在工程引入gtest和gmock&#xff0c;并提供入门参考示例。根据黄金圈思维我们先思考Why&#xff08;为什么做&#xff09;&#xff0c;为什么我们要进行单元测试&#xff0c;为什么要引入mock手段来测试代码…

Linux:路径末尾加/和不加/的区别

相关阅读 Linuxhttps://blog.csdn.net/weixin_45791458/category_12234591.html?spm1001.2014.3001.5482 普通文件操作 首先说明这个问题只会出现在目录和符号链接中&#xff0c;因为如果想要索引普通文件但却在路径末尾加/则会出现错误&#xff0c;如例1所示。 # 例1 zhang…

Django SQL注入-漏洞分析

1.进入项目界面 图1 项目主界面 2.访问任意不存在的目录路径报错&#xff0c;提示存在demo接口 图2 提示存在接口 3.访问/demo/&#xff0c;提示有一个name参数 图3 发现隐藏参数 4.对接口参数进行fuzz&#xff08;实战思路&#xff09;&#xff0c;vulfocus已经给出了/demo?…

Innodb存储架构

Innodb整体存储架构 Innodb是一款兼顾性能及可靠性的存储引擎&#xff0c;主要分为内存存储结构和磁盘存储结构&#xff0c;二者分别扮演着提高性能和数据持久化的工作 内存结构中定义了缓冲池、变更缓冲区、日志缓冲区、自适应哈希四个缓冲区&#xff0c;它们均是为提升查询…

docker技术(上)

一、docker简介 Docker 是一个开源的应用容器引擎&#xff0c;于 2013 年由 Solomon Hykes 推出并开源。它基于 Go 语言开发&#xff0c;遵从 Apache2.0 协议。Docker 可以让开发者将应用及其依赖包打包到一个可移植的容器中&#xff0c;然后发布到任何流行的 Linux 或 Windows…

文件外发控制怎么做?公司文件外发管控的方法(这五种方法你一定要学会!)

还在担心重要文件发出去就"人间蒸发"&#xff1f; 或者每次发送公司机密都提心吊胆&#xff1f; 其实&#xff0c;文件外发就像放风筝&#xff0c;你需要时刻握住“线头”&#xff0c;确保它不会飞得太远&#xff01; 今天我们来揭秘五种公司文件外发的神级管控方法…

基于SpringBoot的医院挂号就诊系统【附源码】

基于SpringBoot的高校社团管理系统&#xff08;源码L文说明文档&#xff09; 目录 4 系统设计 4.1界面设计原则 4.2功能结构设计 4.3.2 数据库物理设计 第5章 系统实现 5.1用户信息管理 5.2 医生信息管理 5.3公告类型管理 5.1公告信息管理 4…

C++进阶(2):多态

多态的概念 多态分为编译时多态(静态多态)和运行时多态(动态多态)。**编译时多态&#xff1a;**主要就是我们前面讲的函数重载和函数模版。之所以叫编译时多态&#xff0c;是因为实参传给形参的参数匹配是发生在编译时完成的&#xff08;ps&#xff1a;通常把编译时一般归为静…

常见项目场景题1(数据量很大时如何去重,实现超时处理)

数据很多&#xff0c;限制内存&#xff0c;如何去重 对于大数据量去重的场景&#xff0c;我们可以考虑使用位图(Bitmap) Bitmap 是使用二进制来表示某个元素是否存在的数组。用0和1来表示存在与不存在 使用Bitmap的话&#xff0c;一个数字占用1bit&#xff0c;大大减少内存消耗…

JVM 调优篇8 调优案例5- 逃逸分析

一 逃逸分析 1.1 概念 逃逸分析的基本行为就是分析对象动态作用域&#xff1a;当一个对象在方法中被定义后&#xff0c;对象只在方法内部使用&#xff0c;则认为没有发生逃逸。当一个对象在方法中被定义后&#xff0c;它被外部方法所引用&#xff0c;则认为发生逃逸。例如作为…

打造未来企业:业务能力建模的实践应用与数字化转型的落地策略

在当今数字化迅速发展的时代&#xff0c;企业的转型迫在眉睫。通过数字技术提升运营效率、增强客户体验、优化资源配置成为了企业竞争的核心战略。《业务能力指南》为企业提供了清晰的业务能力建模框架&#xff0c;并指导企业如何将其应用于实际操作中&#xff0c;帮助企业在数…

(三)代码实现:Boustrophedon Cellular Decomposition Path Planning用珊格地图生成每个cell的覆盖路径

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 TODO:写完再整理 文章目录 系列文章目录前言算法原理方法一&#xff1a;全地图进行牛耕覆盖步骤方法二&#xff1a;区域分解地图进行牛耕覆盖步骤凸多边形基于栅格地图的…

Windows系统文件夹中的文件名排序

一天张三、李四的同事周五接到王哥的一个任务需求&#xff0c;有一个文件夹&#xff0c;里面有许多图片文件&#xff0c;网页访问某个分类展示文件的时候&#xff0c;王哥希望文件名的展示顺序可以按照Windows资源管理器中文件名升序排序的方式展示。 网站图片目录中有如下图片…

程序遇到问题错误bug时的13种解决方法途径总结以及之前的一些具体例子

目录 1 信心--没有解决不了的bug 2 耐心、不要着急、静下心来、用脑思考 2.1 开始解决问题前不要着急&#xff0c;先思考 2.2 在解决问题的过程中也不要着急&#xff0c;要冷静思考 3 网络搜索 4 大模型问答&#xff1a;必应、kimi、通义千问、文心一言 5 看芯片手册、S…

0921VGG网络实现

深度学习之VGG网络搭建 1.VGG动机2.VGG架构3.代码4.结论1.VGG动机 随着卷积网络在计算机视觉领域的快速发展,越来越多的研究人员开始通过改变模型的网络结构在提高在图像识别任务中的精度,例如使用更小的卷积核和步长[2]。基于类似的想法,论文作者提出可以尝试通过改变卷积…

【设计模式】创建型模式(三):单例模式

创建型模式&#xff08;三&#xff09;&#xff1a;单例模式 1.概念2.案例3.实现方式3.1 懒汉式&#xff0c;线程不安全3.2 懒汉式&#xff0c;线程安全3.3 饿汉式3.4 双检锁/双重校验锁&#xff08;DCL&#xff0c;Double-Checked Locking&#xff09;3.5 登记式/静态内部类3.…

俄罗斯OZON新生儿产品好不好卖,OZON新生儿产品

Top1 遥控水球坦克 Танк на радиоуправлении стреляющий орбизами PANAWEALTH 商品id&#xff1a;1384249985 月销量&#xff1a;692 欢迎各位OZON卖家朋友点击这里选品&#xff1a; &#x1f449; D。DDqbt。COm/74rD 遥控射击水…

【项目管理进阶】风险问题

前言 各位盆友&#xff0c;你们期待的项目管理进阶系列有新的消息&#xff0c;请注意查收&#xff0c;并反馈哦~ 在参加项目的过程中&#xff0c;你是否面临或参加过类似如下的场面&#xff1a; 为了立项&#xff0c;先调研市场、技术、社会、组织内部的现状为了科学的管理项目…

如何使用Claude进行Android App开发 —— 基于Jetpack和Compose的电影App实例

如何使用Claude进行Android App开发 —— 基于Jetpack和Compose的电影App实例 近年来&#xff0c;人工智能&#xff08;AI&#xff09;在软件开发中的应用越来越广泛&#xff0c;帮助开发者在设计、编码、测试和优化中提高生产效率。Claude是Anthropic开发的一款强大的AI助手&…