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

javascript 复制代码
<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

相关推荐
xiaoxue..7 小时前
合并两个升序链表 与 合并k个升序链表
java·javascript·数据结构·链表·面试
要加油哦~8 小时前
AI | 实践教程 - ScreenCoder | 多agents前端代码生成
前端·javascript·人工智能
一个public的class8 小时前
你在浏览器输入一个网址,到底发生了什么?
java·开发语言·javascript
青茶3608 小时前
php怎么实现订单接口状态轮询请求
前端·javascript·php
火车叼位8 小时前
脚本伪装:让 Python 与 Node.js 像原生 Shell 命令一样运行
运维·javascript·python
VT.馒头8 小时前
【力扣】2727. 判断对象是否为空
javascript·数据结构·算法·leetcode·职场和发展
鱼毓屿御9 小时前
如何给用户添加权限
前端·javascript·vue.js
JustHappy9 小时前
「web extensions🛠️」有关浏览器扩展,开发前你需要知道一些......
前端·javascript·开源
xixixin_9 小时前
【JavaScript 】从 || 到??:JavaScript 空值处理的最佳实践升级
开发语言·javascript·ecmascript
belldeep9 小时前
python:用 Flask 3 , mistune 2 和 mermaid.min.js 10.9 来实现 Markdown 中 mermaid 图表的渲染
javascript·python·flask