如何优化复选框(el-checkbox)对于树形结构数据的应用 ?

问题描述

使用 element 复选框组件,但是公司的具体业务为树形复杂的数据结构时,改如何优雅的实现

  • 全选反选
  • 半选状态

    问题出现的环境背景及自己尝试过哪些方法

    个人发现 element 以及其他第三方组件库对于全选这种更适用于扁平化的数据结构
    但是实际业务业务中碰到的数据结构为树,如何更优雅的处理该业务
    楼主自己处理的时候思路主要是

  • watch 整个对象,每次 checkbox 进行勾选后重新计算一次 整体的全选半选逻辑
  • 一级,二级节点全选反选 通过 @chang 去改变最底层的叶子节点的 checked ,然后再计算一遍整个对象的半选状态

注意,假设某个节点为 nodeA ,由于具体业务为权限,所以当 nodeA 的子节点都为选中状态时,nodeA 为选中状态,但是当取消勾选 nodeA 的某个子节点,nodeA 的 checked 属性应仍为 true(这是与扁平化全选反选不同的)

相关代码

粘贴代码文本(请勿用截图)

权限数据结构
{
        "modules": [
          {
            "name": "一级",
            "code": "TASK_CTR",
            "checked": true,
            "groups": [
              {
                "name": "二级",
                "code": "TASK_MGR",
                "checked": true,
                "permissions": [
                  {
                    "code": "TASK_LIST",
                    "description": "三级",
                    "checked": true
                  },
                 
                ]
              }
            ]
          },
        ]
      };



个人处理方法
<template>
  <div class="permission-box">
    <div 
      v-for="(item, ) in authList"
      :key="item.code"
      class="permission-box-project" >
      <el-checkbox 
        v-model="item.checked"
        :indeterminate="item.indeterminate"
        @change="handleCheckAll($event,item.permissionVo.modules,'modules')"
      >{{item.name}}</el-checkbox>
      <div v-if="item.permissionVo && item.permissionVo.modules">
        <div 
          v-for="(module, ) in item.permissionVo.modules"
          :key="module.code"
          class="permission-box-part">
          <el-checkbox 
            v-model="module.checked"
            :indeterminate="module.indeterminate"
            @change="handleCheckAll($event,module.groups,'groups')"
          >{{ module.name }}
          </el-checkbox>
          <div 
            v-for="(group, ) in module.groups"
            :key="group.code"
            class="permission-box-group">
            <el-checkbox 
              v-model="group.checked"
              :indeterminate="group.indeterminate"
              @change="handleCheckAll($event,group.permissions,'permissions')"
            >
              {{ group.name }}
            </el-checkbox>
            <div 
              class="permission-box-permission-container"
              :class="{'permission-box-profile-container': group.code == 'EXTENSION_LIBRARIES'}">
              <div 
                v-for="(permission, ) in group.permissions"
                :key="permission.code"
                class="permission-box-permission">
                <el-checkbox 
                  v-model="permission.checked"
                >{{ permission.description }}</el-checkbox>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script lang="ts">

export default {

  props: {
    authList: Array as PropType<AuthType[]>
  },
  data() {
    return {
      // search: {},
    };
  },
  watch: {
    authList: {
      handler(val){
        val.forEach(sysAuth => {

          sysAuth.permissionVo.modules.forEach((module) => {
            module.groups.forEach(group => {
              
              const { checked, indeterminate }  = computeChecked(group.permissions);
              group.checked = checked;
              group.indeterminate = indeterminate;
              
            });

            const { checked, indeterminate }  = computeChecked(module.groups);
            module.checked = checked;
            module.indeterminate = indeterminate;
          });

          const { checked, indeterminate }  = computeChecked(sysAuth.permissionVo.modules);
          sysAuth.checked = checked;
          sysAuth.indeterminate = indeterminate;
        });
      },
      deep: true,
      immediate: true
    }
  },
  mounted() {

  },
  methods: {
    handleCheckAll(val, arr, type){
      switch (type) {
        case 'modules':
          arr.forEach(module => {
            module.groups.forEach(group => {
              group.permissions.forEach(permission => {
                permission.checked = val;
              });
            });
           
          });
          break;

        case 'groups':
          arr.forEach(group => {
            group.permissions.forEach(permission => {
              permission.checked = val;
            });
          });
          break;

        case 'permissions':
          arr.forEach(item => {
            item.checked = val;
          });
          break;
        default:
          break;
      }
 
    },
 
  }
};
</script>





export  function computeChecked(arr){
  let checkedCount = 0;
  let hasChildIndeterminate = false;
  arr.forEach(item => {
    if (item.checked) {
      checkedCount++;
    }
    if (item.indeterminate){
      hasChildIndeterminate = true;
    }
  });
  return {
    checked: !!checkedCount,
    indeterminate: hasChildIndeterminate || (!!checkedCount && checkedCount < arr.length)
  };
}

你期待的结果是什么?实际看到的错误信息又是什么?

各位大佬有没有更加优雅或者简单处理方式?
预期效果 树形权限效果图
image.png

阅读 1.3k
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题