一、目标样式
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();
};