树形结构目录,可编辑,可新增
// An highlighted block
import React, { Component } from "react";
import { Tree, Icon } from "antd";
import styles from "./EditableTree.less";
const { TreeNode } = Tree;
class EditableTree extends Component {
data = [
{
value: "1",
defaultValue: "1",
key: "0-1",
parentKey: "0",
isEditable: false,
children: [
{
value: "1-1",
defaultValue: "1-1",
key: "0-1-1",
parentKey: "0-1",
isEditable: false,
},
{
value: "1-2",
defaultValue: "1-2",
key: "0-1-2",
parentKey: "0-1",
isEditable: false,
},
],
},
{
value: "2",
defaultValue: "2",
key: "0-2",
parentKey: "0",
isEditable: false,
children: [
{
value: "2-1",
defaultValue: "2-1",
key: "0-1-3",
parentKey: "0-1",
isEditable: false,
},
],
},
];
expandedKeys = [];
state = {
expandedKeys: [],
data: this.data,
};
componentDidMount() {
this.onExpand(["0-1", "0-2", "0-3"]); // 默认展开
}
onExpand = (expandedKeys) => {
this.expandedKeys = expandedKeys;
this.setState({ expandedKeys: expandedKeys });
};
renderTreeNodes = (data) =>
data.map((item) => {
if (item.isEditable) {//编辑状态下为input
item.title = (
<div>
<input
className={styles.inputField}
value={item.value}
onChange={(e) => this.onChange(e, item.key)}
/>
<Icon
type="close"
style={{ marginLeft: 10 }}
onClick={() => this.onClose(item.key, item.defaultValue)}
/>
<Icon
type="check"
style={{ marginLeft: 10 }}
onClick={() => this.onSave(item.key)}
/>
</div>
);
} else {
item.title = (
<div className={styles.titleContainer}>
<span className={styles.operationSpan}>{item.value}</span>
<span className={styles.operationField}>
{item.parentKey == 0 ? ( //根标签不可编辑
""
) : (
<Icon
style={{ marginLeft: 10 }}
type="edit"
onClick={() => this.onEdit(item.key)}
/>
)}
{item.parentKey == 0 ? ( //只有根标签才可以新增
<Icon
style={{ marginLeft: 10 }}
type="plus"
onClick={() => this.onAdd(item.key)}
/>
) : (
""
)}
{item.parentKey === "0" ? null : (
<Icon
style={{ marginLeft: 10 }}
type="minus"
onClick={() => this.onDelete(item.key)}
/>
)}
</span>
</div>
);
}
//递归
if (item.children) {
return (
<TreeNode title={item.title} key={item.key} dataRef={item}>
{this.renderTreeNodes(item.children)}
</TreeNode>
);
}
return <TreeNode {...item} />;
});
//新增
onAdd = (e) => {
// 防止expandedKeys重复
if (this.state.expandedKeys.indexOf(e) === -1) {
this.expandedKeys.push(e);
}
this.addNode(e, this.data);
this.setState({
expandedKeys: this.expandedKeys,
data: this.data,
});
};
addNode = (key, data) =>
data.map((item) => {
if (item.key === key) {
if (item.children) {
item.children.push({
value: "default",
defaultValue: "default",
key: key + Math.random(100), //唯一的key
parentKey: key,
isEditable: false,
});
} else {
item.children = [];
item.children.push({
value: "default",
defaultValue: "default",
key: key + Math.random(100),
parentKey: key,
isEditable: false,
});
}
return;
}
if (item.children) {
console.log(item.children, "item.children)");
this.addNode(key, item.children);
}
});
//删除
onDelete = (key) => {
console.log("delete");
this.deleteNode(key, this.data);
this.setState({
data: this.data,
});
};
deleteNode = (key, data) =>
data.map((item, index) => {
if (item.key === key) {
data.splice(index, 1);
return;
} else {
if (item.children) {
this.deleteNode(key, item.children);
}
}
});
//编辑
onEdit = (key) => {
console.log("edit");
this.editNode(key, this.data);
this.setState({
data: this.data,
});
};
editNode = (key, data) =>
data.map((item) => {
if (item.key === key) {
item.isEditable = true;
} else {
item.isEditable = false;
}
item.value = item.defaultValue; // 当某节点处于编辑状态,并改变数据,点击编辑其他节点时,此节点变成不可编辑状态,value 需要回退到 defaultvalue
if (item.children) {
this.editNode(key, item.children);
}
});
//关闭编辑
onClose = (key, defaultValue) => {
console.log("close");
this.closeNode(key, defaultValue, this.data);
this.setState({
data: this.data,
});
};
closeNode = (key, defaultValue, data) =>
data.map((item) => {
item.isEditable = false;
if (item.key === key) {
item.value = defaultValue;
}
if (item.children) {
this.closeNode(key, defaultValue, item.children);
}
});
//保存编辑内容
onSave = (key) => {
console.log("save");
this.saveNode(key, this.data);
this.setState({
data: this.data,
});
};
saveNode = (key, data) =>
data.map((item) => {
if (item.key === key) {
item.defaultValue = item.value;
}
if (item.children) {
this.saveNode(key, item.children);
}
item.isEditable = false;
});
onChange = (e, key) => {
console.log("onchange");
this.changeNode(key, e.target.value, this.data);
this.setState({
data: this.data,
});
};
changeNode = (key, value, data) =>
data.map((item) => {
if (item.key === key) {
item.value = value;
}
if (item.children) {
this.changeNode(key, value, item.children);
}
});
render() {
return (
<div className={styles.TreeNode}>
<Tree
expandedKeys={this.state.expandedKeys}
selectedKeys={[]}
onExpand={this.onExpand}
>
{this.renderTreeNodes(this.state.data)}
</Tree>
</div>
);
}
}
export default EditableTree;
// css部分
.TreeNode{
width:330px;
height:700px;
overflow-y: auto;
margin-right: 10px;
margin-top: 55px;
.inputField {
border: none;
border: 1px solid;
background: none;
border-radius: 2px;
line-height: normal;
min-width: 50px;
outline: none;
&:focus {
outline: none;
}
}
.titleContainer {
.operationField {
visibility: hidden;
}
&:hover {
.operationField {
visibility: visible;
color:blue
};
.operationSpan{
color:blue
}
}
}
}
:global {
.ant-tree li .ant-tree-node-content-wrapper:hover {
background-color: unset;
}
}