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

相关推荐
LJ小番茄2 小时前
Vue 常见的几种通信方式(总结)
前端·javascript·vue.js·html
pan_junbiao4 小时前
Vue组件:模板引用ref属性的使用
前端·javascript·vue.js
__lucas5 小时前
javascript-装饰器
开发语言·javascript·ecmascript
春蕾夏荷_7282977255 小时前
electron nsis打包windows应用程序
javascript·windows·electron·nsis
想退休的搬砖人6 小时前
vue组件的生命周期
前端·javascript·vue.js
zhangjin12226 小时前
kettle从入门到精通 第八十五课 ETL之kettle kettle中javascript步骤调用外部javascript/js文件
javascript·数据仓库·etl·kettle调用外部js
CaptainDrake6 小时前
Vue:指令
前端·javascript·vue.js
软件技术NINI6 小时前
HTML——基本标签
前端·javascript·html
覆水难收呀7 小时前
三、(JS)JS中常见的表单事件
开发语言·前端·javascript
WebGIS皮卡茂10 小时前
【数据可视化】Arcgis api4.x 热力图、时间动态热力图、timeSlider时间滑块控件应用 (超详细、附免费教学数据、收藏!)
javascript·vue.js·arcgis·信息可视化