0
点赞
收藏
分享

微信扫一扫

ElementuUI el-table 树型表格 checkbox多选框选择逻辑

源码之路 2022-03-21 阅读 76

ElementuUI el-table 树型表格 checkbox多选框选择逻辑

如图所示:
在这里插入图片描述

逻辑:

子节点全部选择 => 父节点选择
子节点部分选择 => 父节点半选择
子节点全未选择 => 父节点不选择

代码部分如下:
<template>
  <div class="container">
    <el-table
          :data="tableData"
          border
          style="width: 100%"
          row-key="id"
          default-expand-all
          :tree-props="{ children: 'children' ,hasChildren: 'children.length>0'}"
          ref="tableRef"
          @select="handletableSelect"
          @select-all="handletableSelectAll"
          @selection-change="handletableSelectionChange">
          
         <!-- 多选框列 -->
         <el-table-column
            type="selection"/>
 	     <!-- 
 	      id列 注意:该列很重要,必须是row-key 若不需要展示该列,
 	      则需要通过其他手段在行内标记row-key并自行修改
 	      updateCheckboxIndeterminate方法里的逻辑
 	      下边“半选择”状态需要用到
 	      -->
         <el-table-column
            prop="id"
            label="id"
          ></el-table-column>

		 <!-- ...其他字段 -->
		 
    </el-table>
  </div>
</template>

<script>
export default {
  name: "TreeTableCheckbox",
  data() {
    return {
      tableData: [
        {
          id: 1,
          date: '2016-05-02',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1518 弄'
        }, {
          id: 2,
          date: '2016-05-04',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1517 弄'
        }, {
          id: 3,
          date: '2016-05-01',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1519 弄',
          children: [
            {
            id: 31,
            date: '2016-05-01',
            name: '王小虎',
            address: '上海市普陀区金沙江路 1519 弄'
          }, {
            id: 32,
            date: '2016-05-01',
            name: '王小虎',
            address: '上海市普陀区金沙江路 1519 弄'
          }
          ]
        }, {
          id: 4,
          date: '2016-05-03',
          name: '王小虎',
          address: '上海市普陀区金沙江路 1516 弄'
        }
      ]
      tableSelect: [],
    }
  },
  methods: {
    // 当用户手动勾选数据行的 Checkbox 时触发的事件
    handletableSelect(selection, row) {
      if (row.children) { //只对有子节点的行响应
        // if (row.isChecked === undefined) row.isChecked = true
        if (!row.isChecked) {   //由行数据中的元素isChecked判断当前是否被选中
          this.traverseChildNodes(row.children, this.$refs.tableRef, true)
          row.isChecked = true; //当前行isChecked标志元素切换为false
        } else {
          this.traverseChildNodes(row.children, this.$refs.tableRef, false)
          row.isChecked = false;
        }
      }
      // 处理父级选择逻辑
      // tableSelect 字段是 handletableSelectionChange 回调回来的
      // 如果不用 this.$nextTick 无法获取到正确数据
      this.$nextTick(() => {
        // 递归寻找当前子节点的父级节点
        let getParentNode = function (data, id) {
          for (let i in data) {
            if (data.hasOwnProperty(i)) {
              if (data[i].id === id) {
                return [data[i]]
              }
              if (data[i].children) {
                let node = getParentNode(data[i].children, id);
                if (node !== undefined) {
                  return node.concat(data[i])
                }
              }
            }
          }
        }
        // 设置checkbox半选择状态
        // 此处的传入的id就是匹配表格id字段的
        let updateCheckboxIndeterminate = function (id, isIndeterminate) {
          setTimeout(() => {
            // el-table不支持checkbox半选 目前方案是遍历dom获取行节点设置样式
            let elementsRow = document.getElementsByClassName("el-table__row");
            for (let i = 0; i < elementsRow.length; i++) {
              let element = elementsRow.item(i);
              // tips: 通过其他手段设置行内row-id的 以下代码需要修改
              let childNode = element.childNodes.item(1); // row-key 字段在dom中的索引   第二列=1
              if (childNode.innerText === `${id}`) {
                let td = element.childNodes.item(0) // 获取要设置半选中状态的checkbox
                let div = td.firstChild; // <div class="cell">
                let label = div.firstChild; // <label class="el-checkbox">
                let span = label.firstChild; // <span class="el-checkbox__input">
                if (isIndeterminate)
                  span.classList.add("is-indeterminate")  // 设置半选中状态
                else
                  span.classList.remove("is-indeterminate")  // 取消半选中状态
              }
            }
          }, 1)

        }
        let parentNode = getParentNode(this.$refs.tableRef.data, row.id)
        // > 1 说明节点有子节点
        if (parentNode.length > 1) {
          // 提取兄弟节点ids
          let siblingNodeIds = parentNode[1].children.map(item => item.id)
          // 提取全选所选择项的ids
          let checkedIds = this.tableSelect.map(item => item.id)
          // 获取兄弟行选择数
          let siblingNodeCheckedIds = siblingNodeIds.filter(id => checkedIds.indexOf(id) !== -1)
          if (siblingNodeCheckedIds.length === siblingNodeIds.length) {
            // 兄弟节点选择数===兄弟节点数   全选
            updateCheckboxIndeterminate(parentNode[1].id, false)
            parentNode[1].isChecked = true
            this.$refs.tableRef.toggleRowSelection(parentNode[1], true)
          } else if (siblingNodeCheckedIds.length === 0) {
            // 兄弟节点选择数===0   全不选
            parentNode[1].isChecked = false
            this.$refs.tableRef.toggleRowSelection(parentNode[1], false)
            updateCheckboxIndeterminate(parentNode[1].id, false)
          } else if (siblingNodeCheckedIds.length < siblingNodeIds.length) {
            parentNode[1].isChecked = true
            this.$refs.tableRef.toggleRowSelection(parentNode[1], true)
            for (let i = 0; i < parentNode.length; i++) {
              if (i > 0) updateCheckboxIndeterminate(parentNode[i].id, true)
            }
          }
        }
      })
    },
    // 当用户手动勾选全选 Checkbox 时触发的事件
    handletableSelectAll(selection) {
      this.$refs.tableRef.data.map(items => {
        if (items.children && items.children.length > 0) {
          if (!items.isChecked) {
            this.$refs.tableRef.toggleRowSelection(items, true);
            items.isChecked = true
            this.traverseChildNodes(items.children, this.$refs.tableRef, true)
          } else {
            this.$refs.tableRef.toggleRowSelection(items, false);
            items.isChecked = false;
            this.traverseChildNodes(items.children, this.$refs.tableRef, false)
          }
        } else {
          items.isChecked = !items.isChecked;
        }
      })
    },
    // 当选择项发生变化时会触发该事件
    handletableSelectionChange(selection) {
      this.tableSelect = selection
    },
    // 递归设置子节点
    traverseChildNodes(children, ref, selected) {
      children.map(item => {
        ref.toggleRowSelection(item, selected);
        item.isChecked = selected;
        if (item.children) {
          this.traverseChildNodes(item.children, ref, selected)
        }
      })
    },
  },
}
</script>

<style scoped>
  
</style>

可能有更好的实现逻辑,欢迎交流。

举报

相关推荐

0 条评论