效果
如图所示
实现
import { createRoot } from 'react-dom/client';
import React, { useState } from 'react';
import { Tree, Input, Button } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
const { TreeNode } = Tree;
const { Search } = Input;
const initialData = [
{
title: 'Root Node',
key: '0',
children: [{
title: ' Node',
key: '1',
}],
},
];
const DynamicTree = () => {
const [treeData, setTreeData] = useState(initialData);
const [expandedKeys, setExpandedKeys] = useState(['0']);
const [autoExpandParent, setAutoExpandParent] = useState(true);
const onExpand = (expandedKeys) => {
setExpandedKeys(expandedKeys);
setAutoExpandParent(false);
};
const addNode = (key, title = 'New Node') => {
const addNodeRecursively = (nodes) => {
return nodes.map((node) => {
if (node.key === key) {
const newNode = {
title,
key: `${key}-${node.children ? node.children.length : 0}`,
children: [],
};
return {
...node,
children: [...node.children, newNode],
};
} else if (node.children) {
return {
...node,
children: addNodeRecursively(node.children),
};
}
return node;
});
};
setTreeData((prevData) => addNodeRecursively(prevData));
setExpandedKeys((prevKeys) => [...prevKeys, key]);
};
const renderTreeNodes = (data) =>
data.map((item) => (
<TreeNode title={item.title} key={item.key} dataRef={item}>
{item.children ? renderTreeNodes(item.children) : null}
<TreeNode
title={
<Button
type="dashed"
size="small"
onClick={() => addNode(item.key)}
icon={<PlusOutlined />}
>
Add Child
</Button>
}
key={`${item.key}-add`}
/>
</TreeNode>
));
return (
<div>
<Tree
showIcon
onExpand={onExpand}
expandedKeys={expandedKeys}
autoExpandParent={autoExpandParent}
>
{renderTreeNodes(treeData)}
</Tree>
</div>
);
};
export default DynamicTree;
const ComponentDemo = DynamicTree;
createRoot(mountNode).render(<ComponentDemo />);
进一步增强实现
同层级可以拖拽
增加节点的节点始终放在最后且可以增加同级节点
而且只有末级可以增加
import { createRoot } from 'react-dom/client';
import React, { useState } from 'react';
import { Tree, Button } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
const { TreeNode } = Tree;
const initialData = [
{
title: 'Root Node',
key: '0',
children: [],
},
];
const DynamicTree = () => {
const [treeData, setTreeData] = useState(initialData);
const [expandedKeys, setExpandedKeys] = useState(['0']);
const [autoExpandParent, setAutoExpandParent] = useState(true);
const onExpand = (expandedKeys) => {
setExpandedKeys(expandedKeys);
setAutoExpandParent(false);
};
const addNode = (key, title = 'New Node') => {
const addNodeRecursively = (nodes) => {
return nodes.map((node) => {
if (node.key === key) {
const newNode = {
title:`${title}-${key}-${node.children ? node.children.length : 0}`,
key: `${key}-${node.children ? node.children.length : 0}`,
children: [],
};
return {
...node,
children: [...node.children, newNode],
};
} else if (node.children) {
return {
...node,
children: addNodeRecursively(node.children),
};
}
return node;
});
};
setTreeData((prevData) => addNodeRecursively(prevData));
setExpandedKeys((prevKeys) => [...prevKeys, key]);
};
const renderTreeNodes = (data, level = 0) =>
data.map((item) => (
<TreeNode title={item.title} key={item.key} dataRef={item}>
{item.children ? renderTreeNodes(item.children, level + 1) : null}
{level < 1 && (
<TreeNode
selectable={false}
disabled={true}
icon={<PlusOutlined />}
title={
<Button
type="dashed"
size="small"
onClick={() => addNode(item.key)}
icon={<PlusOutlined />}
>
Add Child
</Button>
}
key={`${item.key}-add`}
/>
)}
</TreeNode>
));
const onDrop = (info) => {
const dropKey = info.node.key;
const dragKey = info.dragNode.key;
const dropPos = info.node.pos.split('-');
const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]);
const loop = (data, key, callback) => {
data.forEach((item, index, arr) => {
if (item.key === key) {
return callback(item, index, arr);
}
if (item.children) {
return loop(item.children, key, callback);
}
});
};
const data = [...treeData];
let dragNode;
// Find dragObject
loop(data, dragKey, (item, index, arr) => {
arr.splice(index, 1);
dragNode = item;
});
if (!info.dropToGap) {
// Drop on the content
loop(data, dropKey, (item) => {
item.children = item.children || [];
// where to insert 示例添加到头部,可以是随意位置
item.children.unshift(dragNode);
});
} else if (
(info.node.children || []).length > 0 && // Has children
info.node.expanded && // Is expanded
dropPosition === 1 // On the bottom gap
) {
loop(data, dropKey, (item) => {
item.children = item.children || [];
// where to insert 示例添加到头部,可以是随意位置
item.children.unshift(dragNode);
});
} else {
let ar;
let i;
loop(data, dropKey, (item, index, arr) => {
ar = arr;
i = index;
});
if (dropPosition === -1) {
ar.splice(i, 0, dragNode);
} else {
ar.splice(i + 1, 0, dragNode);
}
}
setTreeData(data);
};
return (
<div>
<Tree
draggable
onExpand={onExpand}
expandedKeys={expandedKeys}
autoExpandParent={autoExpandParent}
onDrop={onDrop}
>
{renderTreeNodes(treeData)}
</Tree>
</div>
);
};
export default DynamicTree;
const ComponentDemo = DynamicTree;
createRoot(mountNode).render(<ComponentDemo />);