这是树形图片
代码参考@赐你岁月如歌,链接:
React项目引入antd的树形控件实现节点增删改_a253399414的博客-CSDN博客
前言浏览一些主流面试题的时候,发现有的面试题让动手写一个基于antd的树形控件的增删改功能,本来以为antd的组件应该挺简单的,没想到动手做的时候还是费了不少力气。所以就打算记录一下,实现需求的整个过程。一、 引入antd的树形控件使用过antd的小伙伴应该都知道,使用antd就是把它的代码示例粘贴下来,然后根据自己的需求和antd提供的API进行更改。所以这里我也是找一个简单antd树形控件代码示例,不管三七二十一先粘贴进去看看结果怎么样。import React from "react";im
https://blog.csdn.net/a253399414/article/details/115523069
以下是代码
import styled from "@emotion/styled";
import React, { useState } from "react";
import CommonModal from "@/components/CommonModal";
import { Tree, Button } from "antd";
import {
EditOutlined,
PlusOutlined,
MinusOutlined,
CloseOutlined,
CheckOutlined,
DownCircleOutlined,
} from "@ant-design/icons";
import { nanoid } from "nanoid";
// interface DataNode {
// title: string;
// key: string;
// isLeaf?: boolean;
// children?: DataNode[];
// icon: any;
// }
const Doctree = styled(Tree)`
.ant-tree-list-holder {
min-height: 800px;
}
.ant-tree-list-scrollbar {
background-color: #004c87;
position: absolute !important;
display: block !important;
width: 6px !important;
right: -20px !important;
}
.ant-tree-list-scrollbar-thumb {
background-color: #0072ca !important;
width: 6px !important;
height: 201px !important;
}
.ant-tree-node-content-wrapper {
background: transparent !important;
color: #faf219;
}
.ant-tree-node-content-wrapper:hover {
background: transparent !important;
color: #faf219;
}
.ant-tree-node-content-wrapper:focus {
color: #faf219 !important;
}
.anticon-down-circle {
font-size: 16px !important;
}
background: transparent !important;
.ant-tree-list-holder {
margin: 65px 0 0 70px;
font-size: 16px;
color: #b2e3ff;
}
.ant-tree-treenode {
padding: 0 0px 25px 2px !important;
}
`;
const { TreeNode } = Tree;
const treeData = [
{
value: "0",
defaultValue: "0",
key: "0",
parentKey: "0",
isEditable: false,
children: [
{
value: "0-1",
key: "0-1",
defaultValue: "0-1",
isEditable: false,
},
{
value: "0-2",
key: "0-2",
defaultValue: "0-2",
isEditable: false,
},
],
},
];
const expandedKeyArr = ["0"];
export default function Demo() {
const [data, setData] = useState(treeData);
const [expandedKeys, setExpandedKeys] = useState(expandedKeyArr);
const onExpand = (expandedKeys: any) => {
//记录折叠的key值
setExpandedKeys(expandedKeys);
};
const renderTreeNodes = (data: any) => {
let nodeArr = data.map((item: any) => {
if (item.isEditable) {
item.title = (
<div>
<input
value={item.value || ""}
onChange={(e) => onChange(e, item.key)}
/>
<CloseOutlined
style={{ marginLeft: 10 }}
onClick={() => onClose(item.key, item.defaultValue)}
/>
<CheckOutlined
style={{ marginLeft: 10 }}
onClick={() => onSave(item.key)}
/>
</div>
);
} else {
item.title = (
<div>
<span>{item.value}</span>
<span>
<EditOutlined
style={{ marginLeft: 10 }}
onClick={() => onEdit(item.key)}
/>
<PlusOutlined
style={{ marginLeft: 10 }}
onClick={() => onAdd(item.key)}
/>
{item.parentKey === "0" ? null : (
<MinusOutlined
style={{ marginLeft: 10 }}
onClick={() => onClickDelete(item.key)}
/>
)}
</span>
</div>
);
}
if (item.children) {
return (
<TreeNode title={item.title} key={item.key}>
{renderTreeNodes(item.children)}
</TreeNode>
);
}
return <TreeNode title={item.title} key={item.key} />;
});
return nodeArr;
};
const onAdd = (key: any) => {
if (expandedKeys.indexOf(key) === -1) {
expandedKeyArr.push(key);
}
setExpandedKeys(expandedKeyArr.slice());
addNode(key, treeData);
//useState里数据务必为immutable (不可赋值的对象),所以必须加上slice()返回一个新的数组对象
setData(treeData.slice());
};
const onEdit = (key: any) => {
editNode(key, treeData);
setData(treeData.slice());
};
const editNode = (key: any, data: any) =>
data.forEach((item: any) => {
if (item.key === key) {
item.isEditable = true;
} else {
item.isEditable = false;
}
item.value = item.defaultValue; // 当某节点处于编辑状态,并改变数据,点击编辑其他节点时,此节点变成不可编辑状态,value 需要回退到 defaultvalue
if (item.children) {
editNode(key, item.children);
}
});
const addNode = (key: any, data: any) =>
data.forEach((item: any) => {
if (item.key === key) {
if (item.children) {
item.children.push({
value: "default",
key: nanoid(), // 这个 key 是唯一的
});
} else {
item.children = [];
item.children.push({
value: "default",
key: nanoid(),
});
}
return;
}
if (item.children) {
addNode(key, item.children);
}
});
const onChange = (e: any, key: any) => {
changeNode(key, e.target.value, treeData);
setData(treeData.slice());
};
const changeNode = (key: any, value: any, data: any) =>
data.forEach((item: any) => {
if (item.key === key) {
item.value = value;
}
if (item.children) {
changeNode(key, value, item.children);
}
});
const onSave = (key: any) => {
saveNode(key, treeData);
setData(treeData.slice());
};
const saveNode = (key: any, data: any) =>
data.forEach((item: any) => {
if (item.key === key) {
item.defaultValue = item.value;
}
if (item.children) {
saveNode(key, item.children);
}
item.isEditable = false;
});
const onClose = (key: any, defaultValue: any) => {
closeNode(key, defaultValue, treeData);
setData(treeData);
};
const closeNode = (key: any, defaultValue: any, data: any) =>
data.forEach((item: any) => {
item.isEditable = false;
if (item.key === key) {
item.value = defaultValue;
}
if (item.children) {
closeNode(key, defaultValue, item.children);
}
});
const [isModalVisible, setIsModalVisible] = useState(false);
const [confirmLoading, setConfirmLoading] = useState(false);
const [treeKey, steTreeKey] = useState();
const onClickDelete = (key: any) => {
setIsModalVisible(true);
steTreeKey(key);
};
const deleteNode = (key: any, data: any) =>
data.forEach((item: any, index: any) => {
if (item.key === key) {
data.splice(index, 1);
return;
} else {
if (item.children) {
deleteNode(key, item.children);
}
}
});
const onDelete = (treeKey: any) => {
setData(treeData.slice());
// console.log(treeKey);
deleteNode(treeKey, treeData);
};
const handleOk = (key: any) => {
setConfirmLoading(true);
setTimeout(() => {
onDelete(treeKey);
setIsModalVisible(false);
setConfirmLoading(false);
}, 2000);
};
const handleCancel = () => {
setIsModalVisible(false);
};
return (
<div>
<Doctree
switcherIcon={<DownCircleOutlined />}
expandedKeys={expandedKeys}
onExpand={onExpand}
height={753}
treeData={data}
>
{renderTreeNodes(data)}
</Doctree>
<CommonModal
closable={false}
centered={true}
mask={false}
footer={null}
title={null}
visible={isModalVisible}
>
<p className={"modaltitle"}>提示</p>
<p className={"modalcontent"}>是否确定删除?</p>
<Button
className={"queding"}
loading={confirmLoading}
onClick={handleOk}
>
确定
</Button>
<Button className={"quxiao"} onClick={handleCancel}>
取消
</Button>
</CommonModal>
</div>
);
}