el-table 树形结构复选框父子级联动

1,449 阅读11分钟

一、实现效果

父级选中后,子集内容全部选中;子集取消选中后,父级为半选状态;子集全部选中后;父级选中;

0c89d8fc-30d5-40cb-b102-61855c0e3fa3.gif

二、参考文章

el-table 树形结构 多选 父子级联动 全选 半选状态-CSDN博客

三、实现功能分析

3.1 实现过程

   //选择
    selectFun(selection, row) {
      this.setRowIsSelect(row);
    },
    // 设置当前行选中
    setRowIsSelect(row) {
      //当点击父级点复选框时,当前的状态可能为未知状态,所以当前行状态设为false并选中,即可实现子级点全选效果
      if (row.isSelect === "") {
        row.isSelect = false;
        this.$refs.multipleTable.toggleRowSelection(row, true);
      }
      row.isSelect = !row.isSelect;
      let that = this;
     // 递归设置所有子节点选中
      function selectAllChildrens(data) {
        data.forEach((item) => {
          item.isSelect = row.isSelect;
          that.$refs.multipleTable.toggleRowSelection(item, row.isSelect);
          if (item.children && item.children.length) {
            selectAllChildrens(item.children);
          }
        });
      }

      function getSelectStatus(selectStatuaArr, data) {
        if (data) {
          data.forEach((childrenItem) => {
            selectStatuaArr.push(childrenItem.isSelect);
            if (childrenItem.children && childrenItem.children.length) {
              getSelectStatus(selectStatuaArr, childrenItem.children);
            }
          });
        }

        return selectStatuaArr;
      }
      function getLevelStatus(row) {
        //如果当前节点的parantId =0 并且有子节点,则为1
        //如果当前节点的parantId !=0 并且子节点没有子节点 则为3
        if (row.parentId == 0) {
          if (row.children && row.children.length) {
            return 1;
          } else {
            return 4;
          }
        } else {
          if (!row.children || !row.children.length) {
            return 3;
          } else {
            return 2;
          }
        }
      }
      let result = {};
      //获取明确的节点
      function getExplicitNode(data, parentId) {
        data.forEach((item) => {
          if (item.id == parentId) {
            result = item;
          }
          if (item.children && item.children.length) {
            getExplicitNode(item.children, parentId);
          }
        })
        return result;
      }
      function operateLastLeve(row) {
        //操作的是子节点  1、获取父节点  2、判断子节点选中个数,如果全部选中则父节点设为选中状态,如果都不选中,则为不选中状态,如果部分选择,则设为不明确状态
        let selectStatuaArr = [];
        let item = getExplicitNode(that.allData.workbenchList[that.modalIndex].appMenu, row.parentId);
        selectStatuaArr = getSelectStatus(selectStatuaArr, item.children);
        if (
          selectStatuaArr.every((selectItem) => {
            return true == selectItem;
          })
        ) {
          item.isSelect = true;
          that.$refs.multipleTable.toggleRowSelection(item, true);
        } else if (
          selectStatuaArr.every((selectItem) => {
            return false == selectItem;
          })
        ) {
          item.isSelect = false;
          that.$refs.multipleTable.toggleRowSelection(item, false);
        } else {
          item.isSelect = "";
        }
        //则还有父级
        if (item.parentId != 0) {
          operateLastLeve(item)
        }
      }
      //判断操作的是子级点复选框还是父级点复选框,如果是父级点,则控制子级点的全选和不全选

      //1、只是父级 2、既是子集,又是父级 3、只是子级
      let levelSataus = getLevelStatus(row);
      if (levelSataus == 1) {
        selectAllChildrens(row.children);
      } else if (levelSataus == 2) {
        selectAllChildrens(row.children);
        operateLastLeve(row);
      } else if (levelSataus == 3) {
        operateLastLeve(row);
      }
    },

    checkIsAllSelect() {
      this.oneProductIsSelect = [];
      this.allData.workbenchList[this.modalIndex].appMenu.forEach((item) => {
        this.oneProductIsSelect.push(item.isSelect);
      });
      //判断一级产品是否是全选.如果一级产品全为true,则设置为取消全选,否则全选
      let isAllSelect = this.oneProductIsSelect.every((selectStatusItem) => {
        return true == selectStatusItem;
      });
      return isAllSelect;
    },
    // 全选
    selectAllFun(selection) {

      let isAllSelect = this.checkIsAllSelect();
      this.allData.workbenchList[this.modalIndex].appMenu.forEach((item) => {
        item.isSelect = isAllSelect;
        this.$refs.multipleTable.toggleRowSelection(item, !isAllSelect);
        this.selectFun(selection, item);
      });
    },
    // 添加样式
    rowClassNameFun({ row }) {
      if (row.isSelect === "") {
        return "indeterminate";
      }
    },
    headerRowClassName({ row }) {
      let oneProductIsSelect = [];
      this.allData.workbenchList[this.modalIndex].appMenu.forEach((item) => {
        oneProductIsSelect.push(item.isSelect);
      });
      if (oneProductIsSelect.includes("")) {
        return "indeterminate";
      }
      return "";
    },

3.2 HTML && 数据


  <div class="z-box">      
        <div class="z-table">
          <el-table :row-class-name="rowClassNameFun" :header-row-class-name="headerRowClassName"
            :data="allData.workbenchList[modalIndex].appMenu" :row-key="row => { return row.id }"
            :tree-props="{ children: 'children' }" ref="multipleTable" key="1" @select="selectFun"
            @select-all="selectAllFun" stripe :height="multipleTableHeight">
            <el-table-column type="selection" width="55" align="center" fixed="left">
            </el-table-column>
            <el-table-column prop="label" label="选择菜单" min-width="200" align="left">
            </el-table-column>

            <el-table-column prop="type" label="菜单类型" width="160" align="center">
              <template slot-scope="scope">
                <span v-if="scope.row.type == 1">表单</span>
                <span v-else-if="scope.row.type == 2">应用</span>
                <span v-else-if="scope.row.type == 3">自定义链接</span>
                <span v-else-if="scope.row.type == 4">门户网页</span>
                <span v-else>-</span>
              </template>
            </el-table-column>
            <el-table-column prop="contentId" label="原业务ID" width="120" align="center">
            </el-table-column>
            <el-table-column prop="isCopyed" label="是否复制过" width="120" align="center">
              <template slot-scope="scope">
                <span v-if="scope.row.isCopyed == 1"></span>
                <span v-else></span>
              </template>
            </el-table-column>
            <el-table-column prop="isCopyed" label="复制后的业务状态" width="140" align="center">
              <template slot-scope="scope">
                <span v-if="scope.row.isExit == 1 && scope.row.isCopyed == 1">正常</span>
                <span v-else-if="scope.row.isCopyed == 1 && scope.row.isExit == 0">已被删除</span>
                <span v-else> - </span>
              </template>
            </el-table-column>
            <el-table-column prop="copyedContentId" label="复制后的业务id" width="120" align="center">
            </el-table-column>          
          </el-table>
        </div>
      </div>
      
      

      // 全部数据
      allData: {
        workbenchList: [
          {
            "id": 143374,
            "name": "田12345",
            "domain": "http://ntxwh.v.chaoxing.com",
            "roleNames": "超级管理员、测试9",
            "copyNameSign": 0,
            "appMenu": [
              {
                "id": 1638845,
                "label": "cs",
                "level": 0,
                "copyDataSign": -1,
                "isSelect":false,
                "children": [
                  {
                    "id": 2020481,
                    "label": "新建方案",
                    "level": 1,
                    "copyDataSign": -1,
                    type: 1, //1表单2应用3自定义链接4门户网页
                    contentId: 111, //根据type来表单传表单id 应用传应用id 门户可能传他们的webSiteId
                    isCopyed: 1, //1是0否
                    isExit: 1, //没复制过或者复制过内容被删除都是0
                    copyedId: 1232, //如果是1的话才有 注:参数意义是复制过之前复制给目标单位的id类型和当前所处的集合一直
                    copyedContentId: 112, //同copyedId
                    "isSelect":false,
                    "children": [],
                  }, {
                    "id": 2020482,
                    "label": "二级菜单",
                    "level": 1,
                    "copyDataSign": -1,
                    type: 1, //1表单2应用3自定义链接4门户网页
                    contentId: 111, //根据type来表单传表单id 应用传应用id 门户可能传他们的webSiteId
                    isCopyed: 1, //1是0否
                    isExit: 0, //没复制过或者复制过内容被删除都是0
                    copyedId: 1232, //如果是1的话才有 注:参数意义是复制过之前复制给目标单位的id类型和当前所处的集合一直
                    copyedContentId: 112, //同copyedId
                    "isSelect":false,
                    "children": [],
                  }
                ]
              },
              {
                "id": 1084914,
                "label": "测试3",
                "level": 0,
                "copyDataSign": -1,
                type: 2, //1表单2应用3自定义链接4门户网页
                contentId: 111, //根据type来表单传表单id 应用传应用id 门户可能传他们的webSiteId
                isCopyed: 0, //1是0否
                isExit: 0, //没复制过或者复制过内容被删除都是0
                copyedId: 1232, //如果是1的话才有 注:参数意义是复制过之前复制给目标单位的id类型和当前所处的集合一直
                copyedContentId: 112, //同copyedId
                "isSelect":false,
                "children": []
              },
              {
                "id": 1076724,
                "label": "测试4",
                "level": 0,
                "copyDataSign": -1,
                type: 1, //1表单2应用3自定义链接4门户网页
                contentId: 111, //根据type来表单传表单id 应用传应用id 门户可能传他们的webSiteId
                isCopyed: 0, //1是0否
                isExit: 0, //没复制过或者复制过内容被删除都是0
                copyedId: 1232, //如果是1的话才有 注:参数意义是复制过之前复制给目标单位的id类型和当前所处的集合一直
                copyedContentId: 112, //同copyedId
                "isSelect":false,
                "children": []
              }
            ]
          },
          {
            "id": 16102,
            "name": "田12345",
            "domain": "http://62966.v.chaoxing.com",
            "roleNames": "超级管理员、测试9、测试13",
            "copyNameSign": 0,
            "appMenu": [
              {
                "id": 1553224,
                "label": "1111",
                "level": 0,
                "copyDataSign": -1,
                "children": [
                  {
                    "id": 1719209,
                    "label": "示范教学包",
                    "level": 1,
                    "copyDataSign": -1,
                    type: 1, //1表单2应用3自定义链接4门户网页
                    contentId: 111, //根据type来表单传表单id 应用传应用id 门户可能传他们的webSiteId
                    isCopyed: 1, //1是0否
                    isExit: 1, //没复制过或者复制过内容被删除都是0
                    copyedId: 1232, //如果是1的话才有 注:参数意义是复制过之前复制给目标单位的id类型和当前所处的集合一直
                    copyedContentId: 112, //同copyedId
"isSelect":false,
                    "children": []
                  },
                  {
                    "id": 1806229,
                    "label": "角色权限管理",
                    "level": 1,
                    "copyDataSign": -1,
                    "children": [],
                    type: 1, //1表单2应用3自定义链接4门户网页
                    contentId: 111, //根据type来表单传表单id 应用传应用id 门户可能传他们的webSiteId
                    isCopyed: 0, //1是0否
                    isExit: 0, //没复制过或者复制过内容被删除都是0
                    copyedId: 1232, //如果是1的话才有 注:参数意义是复制过之前复制给目标单位的id类型和当前所处的集合一直
                    "isSelect":false,
                    copyedContentId: 112, //同copyedId
                  },

                  {
                    "id": 2187955,
                    "label": "新建方案",
                    "level": 1,
                    "copyDataSign": -1,
                    "children": [
                      {
                        "id": 2187956,
                        "label": "新建方案",
                        "level": 2,
                        "copyDataSign": -1,
                        "children": [
                          {
                            "id": 2187957,
                            "label": "新建方案",
                            "level": 3,
                            "copyDataSign": -1,
                            "children": [],
                            type: 1, //1表单2应用3自定义链接4门户网页
                            contentId: 111, //根据type来表单传表单id 应用传应用id 门户可能传他们的webSiteId
                            isCopyed: 0, //1是0否
                            isExit: 0, //没复制过或者复制过内容被删除都是0
                            copyedId: 1232, //如果是1的话才有 注:参数意义是复制过之前复制给目标单位的id类型和当前所处的集合一直
                            "isSelect":false,
                            copyedContentId: 112, //同copyedId
                          }
                        ]
                      }
                    ]
                  },
                  {
                    "id": 2192990,
                    "label": "????",
                    "level": 1,
                    "copyDataSign": -1,
                    "children": [],
                    type: 1, //1表单2应用3自定义链接4门户网页
                    contentId: 111, //根据type来表单传表单id 应用传应用id 门户可能传他们的webSiteId
                    isCopyed: 0, //1是0否
                    isExit: 0, //没复制过或者复制过内容被删除都是0
                    copyedId: 1232, //如果是1的话才有 注:参数意义是复制过之前复制给目标单位的id类型和当前所处的集合一直
                    copyedContentId: 112, //同copyedId
                    "isSelect":false,
                  },

                ]
              },
              {
                "id": 1524544,
                "label": "基础数据",
                "level": 0,
                "copyDataSign": -1,
                "children": [
                  {
                    "id": 1610636,
                    "label": "系统设置",
                    "level": 1,
                    "copyDataSign": -1,
                    "isSelect":false,
                    "children": [
                      {
                        "id": 1610637,
                        "label": "角色管理",
                        "level": 2,
                        "copyDataSign": -1,
                        "children": [],
                        type: 2, //1表单2应用3自定义链接4门户网页
                        contentId: 111, //根据type来表单传表单id 应用传应用id 门户可能传他们的webSiteId
                        isCopyed: 0, //1是0否
                        isExit: 0, //没复制过或者复制过内容被删除都是0
                        copyedId: 1232, //如果是1的话才有 注:参数意义是复制过之前复制给目标单位的id类型和当前所处的集合一直
                        copyedContentId: 112, //同copyedId
                      },
                      {
                        "id": 1610638,
                        "label": "数据字典",
                        "level": 2,
                        "copyDataSign": -1,
                        "isSelect":false,
                        "children": []
                      },

                    ]
                  },
                  {
                    "id": 1610643,
                    "label": "校区数据",
                    "level": 1,
                    "copyDataSign": -1,
                    "children": [], type: 2, //1表单2应用3自定义链接4门户网页
                    contentId: 111, //根据type来表单传表单id 应用传应用id 门户可能传他们的webSiteId
                    isCopyed: 0, //1是0否
                    isExit: 0, //没复制过或者复制过内容被删除都是0
                    copyedId: 1232, //如果是1的话才有 注:参数意义是复制过之前复制给目标单位的id类型和当前所处的集合一直
                    copyedContentId: 112, //同copyedId
                    "isSelect":false,
                  },
                  {
                    "id": 1610644,
                    "label": "院系/部门数据",
                    "level": 1,
                    "copyDataSign": -1,
                    "isSelect":false,
                    "children": []
                  },
                  {
                    "id": 1610645,
                    "label": "专业数据",
                    "level": 1,
                    "copyDataSign": -1
                    "isSelect":false,,
                    "children": []
                  },

                ]
              },
              {
                "id": 1076722,
                "label": "测试3",
                "level": 0,
                "copyDataSign": -1,
                "children": [],
                type: 1, //1表单2应用3自定义链接4门户网页
                contentId: 111, //根据type来表单传表单id 应用传应用id 门户可能传他们的webSiteId
                isCopyed: 1, //1是0否
                isExit: 0, //没复制过或者复制过内容被删除都是0
                copyedId: 1232, //如果是1的话才有 注:参数意义是复制过之前复制给目标单位的id类型和当前所处的集合一直
                copyedContentId: 112, //同copyedId
                "isSelect":false,
              },

            ]
          },
        ],
        mobileAppList: [
          {
            "id": 325510,
            "name": "测试",
            "apps": [
              {
                "id": 9009311,
                "name": "测试",
                "icon": "https://pan-yz.chaoxing.com/thumbnail/origin/2d87595486b0f93e4a01d26e1c4b52be",
                type: 3, //应用类型目前产品工厂支持复制的引擎类型有限:1审批2表单3图表4自定义链接5共读
                contentId: 213, //1235只有 自定义链接置空
                isCopyed: 1,
                isExit: 1,
                copyedId: 1232, //这里传的是应用的mappid
                copyedContentId: 112, //不是全部的应用都有引擎生成id 1 2 3 5都是引擎都是有这个id的
                "isSelect":false,

              },
              {
                "id": 8636605,
                "name": "二维码管理",
                "icon": "http://p.ananas.chaoxing.com/star3/origin/3231de53584cbc3a5baee20eb36adea8",
                type: 2, //应用类型目前产品工厂支持复制的引擎类型有限:1审批2表单3图表4自定义链接5共读
                contentId: 213, //1235只有 自定义链接置空
                isCopyed: 0,
                isExit: 1,
                copyedId: 1232, //这里传的是应用的mappid
                copyedContentId: 112, //不是全部的应用都有引擎生成id 1 2 3 5都是引擎都是有这个id的
"isSelect":false,
              },
              {
                "id": 8401331,
                "name": "建设示范教学包",
                "icon": "http://p.ananas.chaoxing.com/star3/origin/2bc7d11ce263079caef25657cd7cb4f5",
                type: 2, //应用类型目前产品工厂支持复制的引擎类型有限:1审批2表单3图表4自定义链接5共读
                contentId: 213, //1235只有 自定义链接置空
                isCopyed: 1,
                isExit: 0,
                copyedId: 1232, //这里传的是应用的mappid
                copyedContentId: 112, //不是全部的应用都有引擎生成id 1 2 3 5都是引擎都是有这个id的
"isSelect":false,
              }
            ]
          },
          {
            "id": 509,
            "name": "默认分类",
            "apps": [
              {
                "id": 6872,
                "name": "请假",
                "icon": "http://p.ananas.chaoxing.com/star3/origin/02ef923269ae791bfa0b33a50615d491",
                type: 2, //应用类型目前产品工厂支持复制的引擎类型有限:1审批2表单3图表4自定义链接5共读
                contentId: 213, //1235只有 自定义链接置空
                isCopyed: 1,
                isExit: 1,
                copyedId: 1232, //这里传的是应用的mappid
                copyedContentId: 112, //不是全部的应用都有引擎生成id 1 2 3 5都是引擎都是有这个id的
                "isSelect":false,

              },
              {
                "id": 6870,
                "name": "wifi打卡",
                "icon": "http://p.ananas.chaoxing.com/star3/origin/17f98dcabed27c62849485f8535d28cc",
                type: 2, //应用类型目前产品工厂支持复制的引擎类型有限:1审批2表单3图表4自定义链接5共读
                contentId: 213, //1235只有 自定义链接置空
                isCopyed: 0,
                isExit: 0,
                copyedId: 1232, //这里传的是应用的mappid
                copyedContentId: 112, //不是全部的应用都有引擎生成id 1 2 3 5都是引擎都是有这个id的
                "isSelect":false,

              },
              {
                "id": 6873,
                "name": "销假",
                "icon": "http://p.ananas.chaoxing.com/star3/origin/fac758d0deab810d7f880b508b624ac2",
                type: 4, //应用类型目前产品工厂支持复制的引擎类型有限:1审批2表单3图表4自定义链接5共读
                contentId: 213, //1235只有 自定义链接置空
                isCopyed: 1,
                isExit: 1,
                copyedId: 1232, //这里传的是应用的mappid
                copyedContentId: 112, //不是全部的应用都有引擎生成id 1 2 3 5都是引擎都是有这个id的
                "isSelect":false,
              },
              {
                "id": 6876,
                "name": "用车",
                "icon": "http://p.ananas.chaoxing.com/star3/origin/031f4bf1141e434b49708597f8f2f262",
                type: 5, //应用类型目前产品工厂支持复制的引擎类型有限:1审批2表单3图表4自定义链接5共读
                contentId: 213, //1235只有 自定义链接置空
                isCopyed: 1,
                isExit: 1,
                copyedId: 1232, //这里传的是应用的mappid
                copyedContentId: 112, //不是全部的应用都有引擎生成id 1 2 3 5都是引擎都是有这个id的
                "isSelect":false,
              }
            ]
          }
        ],       
      },