我认为TreeSelect组件和Tree组件的区别是把Tree组件放到了Select组件里面。
单纯的下拉框中的Tree形结构收起展开热区的扩展和Tree组件是一样的。
可以参考我的上一篇文章:
(11条消息) Antd的Tree组件收起展开热区扩展_憨逗君的博客-CSDN博客
不同的地方是:
热区改变之后,点击节点应该有两种效果:
(1)一种是只控制树形的收起与展开,下拉框不用隐藏,
(2)另一种是点击节点被选中,下拉框隐藏。
我这里是叶子节点被点击时是选中效果,其他节点被点击时就是单纯的控制树形的收起与展开
代码如下:
const [open, setOpen] = useState(false);
//通过open控制下拉框的显示与隐藏,默认值为false
open={open}
// 当select组件被聚焦时下拉框显示
onFocus={() => setOpen(true)}
// 当select组件失焦时下拉框隐藏
还有当组件被点击时,触发onSelect函数,判断是否为叶子节点,如果为叶子节点则将下拉框隐藏,即将open值置为false。
那么我们怎么判断一个当前节点是否为叶子节点呐
onSelect回调函数可以接收两个参数,第一个参数为被点击节点的key值,第二个参数为被点击节点的所有信息。具体有哪些信息是由传入的treeData决定的。
默认的treeData格式如下:
所以onSelect回调函数第二个参数接收的信息也就只有title,value和children,具体如下图:
所以我们可以对传入的treeData数据进行改造,改造函数如下:
// 生成一个含有三级的树状数据,每个节点的值含有自己的title,value和自己的子节点的值
const dig = (path = "0", level = 3) => {
const list = [];
for (let i = 0; i < 10; i += 1) {
const key = `${path}-${i}`;
const treeNode = {
title: key,
value: key,
};
if (level > 0) {
treeNode.children = dig(key, level - 1);
}
list.push(treeNode);
}
return list;
};
const treeData = dig();
const pupinTreeData = [];
// (1)给每个节点加上isLeaf 为true则为子节点,为false则不是子节点
// (2) 把初始的树状数据打平放入pupinTreeData中
// (3) 给每个节点拼接上parentKey,值是改节点的所有父节点的key值拼接成的数组
const formatTreeData = (parentKey = []) => {
treeData.forEach((element) => {
const { value, children = [] } = element;
element.parentKey = parentKey;
let newParentKey = parentKey.concat(value);
if (children.length > 0) {
formatTreeData(children, newParentKey);
element.isLeaf = false;
} else {
element.isLeaf = true;
}
pupinTreeData.push(Object.assign({}, element, { children: [] }));
});
};
formatTreeData();
改造之后onSelect回调函数第二个参数就变为如下:
然后我们在onSelect回调函数中就可以
// 如果该节点为叶子节点,则下拉框的值变为该节点的key值,同时下拉框隐藏
if (node.isLeaf) {
setValue(value);
//让treeSelect组件失焦
treeSelect.current.blur();
}
这样我们就完成了treeSelect组件,在树形节点被点击时,下拉框显示隐藏的交互。
实现方法就是,根据输入的值去匹配树状数据中的节点,将匹配到的节点key值存到expandedKeys中即可。
这样还是有问题,如果一个子节点的key值被存到expandedKeys中,但是他的上层节点的key值没有存放带expandedKeys中的话,这样也是不能完成展开效果的。
所以就需要在格式化树状数据的时候
第一将树状数据铺平,是为了匹配到key值包含输入框中输入值的所有节点,
第二给每个节点的加上parentKey,使得能够在将自身key值放到expandedkey中时,将所有上层节点的key值也一并存进去,然后进行去重,这样才能完成展开效果。具体代码如下:
// 根据输入框的值将所有匹配到的节点的key值存到expandedKeys中
function findAllNodeExpand(val) {
let allExpand = [];
pupinTreeData.forEach((item) => {
if (item.value.indexOf(val) > -1) {
allExpand.push(item.value);
allExpand = allExpand.concat(item.parentKey);
}
});
allExpand = [...new Set(allExpand)];
setExpandedKeys(allExpand);
return allExpand;
}
综上,就完成了Antd的TreeSelect组件收起展开热区扩展
完整代码如下:
import { TreeSelect } from "antd";
import { useState, useRef } from "react";
import { debounce } from "../../utils/debounce";
const dig = (path = "0", level = 3) => {
const list = [];
for (let i = 0; i < 10; i += 1) {
const key = `${path}-${i}`;
const treeNode = {
title: key,
value: key,
};
if (level > 0) {
treeNode.children = dig(key, level - 1);
}
list.push(treeNode);
}
return list;
};
const treeData = dig();
const pupinTreeData = [];
const formatTreeData = (treeData, parentKey = []) => {
treeData.forEach((element) => {
const { value, children = [] } = element;
element.parentKey = parentKey;
let newParentKey = parentKey.concat(value);
if (children.length > 0) {
formatTreeData(children, newParentKey);
element.isLeaf = false;
} else {
element.isLeaf = true;
}
pupinTreeData.push(Object.assign({}, element, { children: [] }));
});
};
formatTreeData(treeData);
console.log("treeData:", treeData);
console.log("pupinTreeData:", pupinTreeData);
const App = () => {
const [value, setValue] = useState("");
const [expandedKeys, setExpandedKeys] = useState([]);
const [open, setOpen] = useState(false);
const treeSelect = useRef();
// 根据输入框的值将所有匹配到的节点的key值存到expandedKeys中
function findAllNodeExpand(val) {
let allExpand = [];
pupinTreeData.forEach((item) => {
if (item.value.indexOf(val) > -1) {
allExpand.push(item.value);
allExpand = allExpand.concat(item.parentKey);
}
});
allExpand = [...new Set(allExpand)];
setExpandedKeys(allExpand);
return allExpand;
}
const debounceTask = debounce(findAllNodeExpand, 1000);
const onSelect = (value, node, extra) => {
console.log("value:", value, node);
console.log("expandedKeys:", expandedKeys);
if (node.isLeaf) {
setValue(value);
// setOpen(false);
treeSelect.current.blur();
}
let copyExpandedKeys = [...expandedKeys];
let expandedIndex = copyExpandedKeys.indexOf(value);
if (expandedIndex > -1) {
copyExpandedKeys.splice(expandedIndex, 1);
setExpandedKeys(copyExpandedKeys);
} else {
copyExpandedKeys.push(value);
setExpandedKeys(copyExpandedKeys);
}
};
const onTreeExpand = (expandedKeys) => {
setExpandedKeys(expandedKeys);
};
return (
setOpen(true)}
// 当select组件失焦时下拉框隐藏
onBlur={() => setOpen(false)}
showSearch
ref={treeSelect}
onSearch={(value) => {
debounceTask(value);
}}
/>
);
};
export default App;