基于ElementUI中Table嵌套实现多选

3,362 阅读4分钟

基于ElementUI中的Table嵌套多选(不包含分页)

前言:

写这个是因为帮朋友修改项目中的bug

我也是第一次写这个功能,有不对的希望大家指正,如果看完有帮助点个赞!

代码中关键是js中Tree的路径查找这个核心,有不懂的自行百度

多了不说了,有需要的可以私信找我要代码,来看下我怎么实现的

思路:

从头开始看这个需求,我们需要知道用到哪写东西

  • 1、表格Table
  • 2、多选&全选
  • 3、嵌套数据(下拉操作) 正好我们可以找下ElementUI官方文档

1.bmp

22.bmp

  • 找到了我们需要用到的API
    • 在嵌套数据的时候需要使用tree-props
    • 选中数据的时候使用toggleRowSelection

基本就以上这些能用到的可以开搞了

实现:

  • 基于以上我们可以写出HTML结构
<template>
  <div>
    <el-table
      ref="multipleTable"
      :data="tableData"
      style="width: 100%; margin-bottom: 20px"
      row-key="id"
      border
      default-expand-all
      :select-on-indeterminate="true"
      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
      @select="rowSelect"
      @select-all="selectAll"
    >
      <el-table-column type="selection" width="55"> </el-table-column>
      <el-table-column prop="date" label="日期" width="180"> </el-table-column>
      <el-table-column prop="name" label="姓名" width="180"> </el-table-column>
      <el-table-column prop="address" label="地址"></el-table-column>
    </el-table>
  </div>
</template>

表格的多选我可以分为2项目,1个是正向选中,意思就是checkout为true的时候,2是反向取消就是checkout为false的时候,那下面我就来分析下这个正向选中和反向取消如何实现

一、正向选中

假设我有这样的数据

以下面图1片为例:
    在点击子节点的时候我们需要把子节点的父节点和跟节点同时进行选中处理
    跟节点-父节点-子节点
    图2是我data中声明的数据,数据中包含isChecked是否被选中和children是否有子节点

44.png

65.bmp

现在我们正向选中思路明确了那我们怎么来实现?

当我点击子节点时候需要记录子节点的父节点一直到跟节点,那我们就用到了Tree树的概念

下面代码用到了树的回溯的思想,查找路径使用先序遍历,因为你不确定你点击的是子节点是在哪个子树上, 具体的Tree方法思想请百度一下;

treeFindPath(tree, func, path = []) {
      if (!tree) return [];
      for (const data of tree) {
        path.push(data);
        if (func(data)) return path;
        if (data.children) {
          const findChildren = this.treeFindPath(data.children, func, path);
          if (findChildren.length) return findChildren;
        }
        path.pop();
      }
      return [];
    },

通过上面这段代码我们调用的时候传节点的id会返回一个数组,数组包含它所在路径上的对象,这样我们就可以通过循环遍历这个数组通过toggleRowSelection反法来实现页面状态样式的改变。

二、反向取消

反向取消正好和选中相反

在点击子节点取消的时候我们需要判断同级的节点是不是都取消了,如果都取消了需要把这个节点的父节点改为取消状态,之后再查其父节点同级是否都是取消状态,如果还有取消状态,同理跟刚才方式一样接着向其上级节点查找直到不满足条件为止,跳出循环。

  • 简单的来个示意图 12121.png

在点击4节点时,会查看同级节点5和6是否是取消状态,如果都是取消状态,查他们的上一级2,把2改为false,在查2的同级3是否是取消如果是取消在查1

如果同级有选中状态会直接跳出循环不进行下一步操作

  • 下面是取消选中代码

还是用Tree的代码,把获取的数组reverse()进行了翻转

第一次循环从点击那个节点网上查找

这里使用for循环如果不满足直接终止后面循环

1212123.bmp

三、全选

这里我感觉写的比较啰嗦,

全选时候我会先通过数据中isChecked来递归判断是否有没有选中的

如果有没有选中会递归执行把所有数据中的isChecked变为true,如果都选中了,会递归修改为false,

  • 下面是全选的所有代码
        /**
     * @describe 全选
     * isAllCheck为false代表是有没选中
     */
    selectAll() {
      let isAllCheck = this.selectAllRecursion(this.outPool);
      this.checkoutAll(this.outPool, !isAllCheck);
    },
    /**
     * @describe 递归判断isChecked是否都是true,false代表是有没选中
     */
    selectAllRecursion(arr) {
      let isCheck = true;
      function isRecursion(arr) {
        arr.forEach((item) => {
          if (!item.isChecked) {
            isCheck = false;
            if (item.children) {
              isRecursion(item.children);
            }
          }
        });
      }
      isRecursion(arr);
      return isCheck;
    },
    /**
     * @describe 全选改为true或者false
     */
    checkoutAll(arr, boole) {
      function allCheck(arr, boole) {
        arr.forEach((item) => {
          if (item.children) {
            allCheck.call(this,item.children, boole);
          }
          item.isChecked = boole;
          this.$refs.multipleTable.toggleRowSelection(item, boole);
        });
      }
      allCheck.call(this,arr, boole);
    },

END:

基本代码就以上这些,不包含表格分页功能

如果有好的写法可以告诉我,有需要代码直接用的可找我,有帮助的话记得点赞