Bootstrap

【vue3 + antd】Tree 树形控件

一、目标样式

目标样式
1、默认展开所有树节点点击文字

2、点击文字也能 “选中/取消选中” 节点

二、问题说明

1、要求 “默认展开所有树节点”,但是只展开到了 “物理、化学、生物” 那一层。即,v-if=“data.length” 判断的层级不够,只判断到了那一层,就只展开到那一层。

2、当整个tree是全选的状态,选中文本节点的时候发现checkbox并没有被取消,除非先勾选一下checkbox。

三、原因分析

1、默认展开所有树节点, 如果是异步数据,需要在数据返回后,再实例化,建议用 v-if="data.length" 。因为,当有 expandedKeys 时,defaultExpandAll 将失效。

2、既然选中文本节点也要 “选中/取消” 勾选checkbox,那就 选中文本节点的时候,手动触发checkbox的click事件

四、解决办法

1、判断最里面的那一层数据都有了,之后再渲染,即,需要判断到所有需要展开的数据最里面的那一层都已经有数据了,如图中的“实验名称”这一层。
解决代码关键点说明
2、点击文本节点的时候,手动触发checkbox的click事件

五、部分代码说明

1、html结构

<a-form :model="ruleData.info" :rules="rules" ref="formRef">
   <a-form-item label="抽查范围:" name="range" class="rule-style">
     <a-tree
       checkable
       v-if="
         ruleData.treeData.length && ruleData.treeData[0].children.length
       "
       :defaultExpandAll="true"
       :tree-data="ruleData.treeData"
       v-model:selectedKeys="ruleData.selectedKeys"
       v-model:checkedKeys="ruleData.info.range"
       @check="clickRange"
       @select="treeSelect"
     >
       <template #headerTitle>
         实验列表
         <span class="title-right">
           {{ `${ruleData.info.rangeExp.length}/${ruleData.treeNum}` }}
         </span>
       </template>
     </a-tree>
   </a-form-item>
</a-form>

2、css样式

  .ant-form {
    width: 970px;
    // 校验样式调整
    /deep/.rule-style{
      // .ant-form-item-control::after{
      //   content: "";
      //   display: block;
      //   position: relative;
      //   height: 24px;
      // }
      // .ant-form-item-explain-error{
      //   position: absolute;
      //   bottom: 0;
      // }
      // .ant-form-item-explain-success{
      //   position: absolute;
      //   bottom: 0;
      // }
      .ant-input-affix-wrapper{
        width: 66px;
        height: 32px;
        border-radius: 4px;
      }
    }
  
    /* 抽查范围 */
    /deep/.ant-tree-switcher{
      display: none !important;
    }
    /deep/.ant-tree {
      width: 880px;
      border: 1px solid #dfe3eb;
  
      .headerTitle{
        padding: 0;
        background: #f4f5fa;
        // 表头行
        &>span:nth-child(2){
          padding-left: 24px;
          .ant-tree-checkbox-inner{
            top: 12px;
          }
          &::after{
            display: none;
          }
        }
        &>span:nth-child(3){
          height: 48px;
          line-height: 48px;
        }
        .title-right{
          position: absolute;
          right: 32px;
        }
        
        
        &>ul{
          padding: 0 48px;
          background-color: #fff;
          display: flex;
          .subjectTitle{
            width: 256px;
            padding: 16px 0;
            // 实验名称过长时换行
            .ant-tree-node-content-wrapper{
              height: auto;
              white-space: pre-wrap;
            }
          }
        }
      }
    }
  }

3、数据结构

// 抽查规则数据
 const ruleData = reactive({
   info: {
     range: [], // 选中复选框的树节点questionId
     rangeExp:[],// 只有选中实验的key
   },
   treeData: [
     {
       title: "实验列表",
       key: "实验",
       slots: { title: "headerTitle" },
       class: "headerTitle",
       children: [],
     },
   ],
   onlyExperiment: [], // 只有实验名称的id
   selectedKeys: [], // 设置选中的树节点
   treeNum: 0, // 实验数量
 });

4、事件功能

/**
* @description: 点击复选框,手动触发校验
* @return {*}
*/
const clickRange = () => {
	formRef.value.validate("range");
	// 只有选中实验的key
	ruleData.info.rangeExp = [];
	ruleData.info.range.map((item) => {
		ruleData.onlyExperiment.map((val) => {
			if (item === val) {
				return ruleData.info.rangeExp.push(item);
			}
		});
	});
};

/**
* @description: 点击文字,能 “选中/取消选中” 节点
* @return {*}
*/
const treeSelect = (selectedKeys, e) => {
    // 转成真正的数组
    const toArray = (list) => Array.from(list || []);
    // 获取被点击的树节点
    // e.nativeEvent.path应该就相当于chrome浏览器中的event.path:表示触发Dom事件的元素一路冒泡到window的所有元素
    // 这里只要取包裹checkbox和文本的父li就可以了,className并不是一定叫“ant-tree-treenode”,可f12查看自行更改
    const node = e.nativeEvent.path.find((item) => {
      return toArray(item.classList).findIndex(className => className === "ant-tree-treenode-switcher-open") !== -1;
    });
    // 获取checkbox复选框
    const checkbox = toArray(node.childNodes).find((item) => {
      return toArray(item.classList).findIndex(className => className === "ant-tree-checkbox") !== -1;
    })
    // 模拟点击
    checkbox && checkbox.click();
    clickRange();
};

六、【点击文字可以“选中/取消选中”节点】参考链接

ant-design-vue tree组件选中节点也可以勾选上checkbox

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;