Tree树形控件被禁用(disabled)父组件无法半选中回显问题

450 阅读3分钟

相关知识点链接

Tree 的勾选传导:ant-design.antgroup.com/docs/blog/c…
注:这个主要是说明为什么在disabled状态下不会传导没有回显的问题

Tree树形控件: next.antdv.com/components/…

解决方法

解决结果

image.png

以下只是部分代码

使用的自定义图标去解决的,根据后端返回的选中的字符串数组formData.menuTitleList,以及返回的mobile_treeData的树形控件数据

<template>
  <a-tree
    v-if="defaultExpandedKeys.length > 0"
    v-model:checkedKeys="formData.menuTitleList"
    :tree-data="mobile_treeData"
    :show-icon="data && data.isStatic"
    :default-expanded-keys="defaultExpandedKeys"
  >
    <!--使用默认图标 给图标添加类名 -->
    <template #icon="{ dataRef, title, key }">
        <!--选中的 -->
      <span
        class="right"
        v-if="formData.menuTitleList.includes(key)"
        :disabled="true"
      ></span>
      <!--半回显:自身没有被选中,子元素有被选中的 -->
      <span
        v-if="!formData.menuTitleList.includes(key) && dataRef.indeterminate"
        :class="dataRef.indeterminate ? 'indeterminate' : ''"
      >
      </span>
      <!--没有选中的子元素也没有选中的 -->
      <span
        class="ranger"
        v-if="!formData.menuTitleList.includes(key) && !dataRef.indeterminate"
        :disabled="true"
      ></span>
    </template>

    <template #title="{ title, key }">
      <span v-if="key === '0-0-1-0'" style="color: #1890ff">{{ title }}</span>
      <span v-else>{{ title }}</span>
    </template>
  </a-tree>
</template>

<script setup>
    import {ref,unref} from 'vue'

    const formData = ref({
        menuTitleList:[]
    })
    
    const mobile_treeData = ref([])
    //给获取的treeData数据设置是否禁用以及解决禁用父节点无法半回显问题
      function disabled_treeData(
        list: any[],
        disabled: boolean = false,
        _obj: any,
        _arr: any[],
      ) {
        list?.forEach((val) => {
          val.disableCheckbox = disabled;
          if (val.children && val.children.length) {
            disabled_treeData(val.children, disabled, val, _arr);
            //这里是为了回显到最外层的父节点,只要有子节点是半回显状态,父节点也应该是半回显状态
            if (val.indeterminate) {
              _obj.indeterminate = true;
            }
          } else {
            // 如果_arr数组中存在等于val.key的值,则给父节点设置半选中状态
            if (_arr.includes(val.key)) {
              _obj.indeterminate = true;
            }
          }
        });
        return list;
      }


    //如果获取到的树形控件数据不会重新获取,,调用这个方法把之前设置了半回显的节点返回最原始的状态
      function disabled_treeDatas(list?: any[], disabled: boolean = false) {
        list?.forEach((val) => {
          val.disableCheckbox = disabled;
          val.indeterminate = false;
          if (val.children && val.children.length) disabled_treeDatas(val.children, disabled);
        });
        return list;
      }
      
      //调用方法
       const getTreeData = () => {
           mobile_treeData.value = disabled_treeData(
              unref(mobile_treeData),
              true,
              unref(mobile_treeData),
              formData.value.menuTitleList,
            *);*
       }
</script>
<style lang='less' scoped>  
    .ant-tree .ant-tree-node-content-wrapper {
      display: flex;
      align-items: center;
    }
  .indeterminate,
  .right,
  .ranger {
    position: relative;
    top: 0;
    left: 0;
    display: block;
    width: 16px;
    height: 16px;
    direction: ltr;
    background-color: #fff;
    border: 1px solid #d9d9d9;
    border-radius: 2px;
    border-collapse: separate;
    transition: all 0.3s;
    background-color: #f5f5f5;
    border-color: #d9d9d9 !important;
    margin-top: 4px;
  }

  .indeterminate:after {
    top: 50%;
    left: 50%;
    width: 8px;
    height: 8px;
    background-color: #d9d9d9;
    border: 0;
    transform: translate(-50%, -50%) scale(1);
    opacity: 1;
    content: ' ';
    position: absolute;
  }

  .right::after {
    position: absolute;
    display: table;
    border: 2px solid #fff;
    border-top: 0;
    border-left: 0;
    transform: rotate(45deg) scale(1) translate(-50%, -50%);
    opacity: 1;
    transition: all 0.2s cubic-bezier(0.12, 0.4, 0.29, 1.46) 0.1s;
    content: ' ';
    border-color: rgba(0, 0, 0, 0.25);
    animation-name: none;
    top: 50%;
    left: 21.5%;
    width: 5.71428571px;
    height: 9.14285714px;
  }
  .ranger::after {
    content: ' ';
    width: 0;
  }
</style>

注意:因为项目中配置角色权限时用到,就进入页面调用获取树形控件的数据的接口,点击不同角色时选中的不一样,所以在弹窗关闭时要调用disabled_treeDatas方法,把数据回归到之前的状态,在弹窗开启时在获取此角色选中列表,再调用disabled_treeData方法去进行父节点的半选中回显

项目中需要默认展开到二级节点

<srcipt setup>
 function disabled_treeData(
    list: any[],
    disabled: boolean = false,
    _obj: any,
    _arr: any[],
    index = 0,
    expandKey: any[],
  ) {
    list?.forEach((val) => {
      val.disableCheckbox = disabled;
      if (val.children && val.children.length) {
        if (index == 0) {
          expandKey.push(val.key);   //默认展开数组
          val.children.forEach((val) => {
            if (val.children && val.children.length) {
              expandKey.push(val.key);
            }
          });
        }

        disabled_treeData(val.children, disabled, val, _arr, index + 1, expandKey);
        if (val.indeterminate) {
          _obj.indeterminate = true;
        }
      } else {
        // 如果_arr数组中存在等于val.key的值,则给父节点设置半选中状态
        if (_arr.includes(val.key)) {
          _obj.indeterminate = true;
        }
        if (index > 1) {
          index -= 1;
        }
      }
    });
    return list;
  }
</script>

注意:disabled_treeData跟上面的是同一个方法,因为需求增加,修改了一些,在弹窗关闭时要把expandKey设置为空,弹窗开启时调用disabled_treeData,为了防止用户展开其他节点或者关闭其他节点,重新进来不是默认展开状态