实现Ant Design Tree组件的节点的增删改
在做项目时最近遇到一个需求,需要用到Antd中的tree,并能够实现对tree的节点的增加和删除,以及节点名称的修改。去翻Antd官网文档,发现tree组件并没有提供关于节点操作的api,但是有鼠标右击的api。借助这个鼠标右击,以及其他组件是可以实现对节点的增删改。下面进行截图介绍:
截图介绍
第一部分:Tree组件
- 最外层节点只能增加子节点
- 父节点可以增加子节点,修改自己的节点名称,删除节点
3.最内层节点不允许再添加子节点,只允许修改自己的节点名称和删除该节点
第二部分:Tooltip组件
4.点击添加子节点。这里用到了Tooltip组件,包装成button,设置点击事件弹出Model框输入节点名称以添加
5.修改节点
6.删除节点
第三部分:Model组件
实现弹出窗交互
具体代码
话不多说,直接上代码,能力有限,仅供参考。
import React, { Component } from 'react'
import {Tree,Tooltip,Modal,Form,Input,message} from 'antd';
import {PlusCircleOutlined,EditOutlined,MinusCircleOutlined}from '@ant-design/icons';
import { reqGetTreeNode,reqAddTreeNode,reqUpdateTreeNode,reqDeleteTreeNode,reqGetPageInfo} from '../../api';
const { DirectoryTree } = Tree;
export default class TreeNode extends Component {
formRef = React.createRef();
state={
role:0,
treeData:[],
defaultExpandedKeys:'',
NodeTreeItem: null, //右键菜单
visible: false,
isModalVisible:false,//是否显示modal 新建组织或者修改组织
isHideAdd:'', //是否展示添加按钮
isHideUpdate:'', //是否展示修改按钮
isHideDelete:'', //是否展示删除按钮
operType:'', //区别Modal弹出框的类型,(添加,修改,删除用的是一个Modal)
text:'',
isLoading:true
}
getTreeNode = async() => {
const result = await reqGetTreeNode();
this.addIsLeaf(result.value)
this.setState({treeData:[{
title: '信息管理',
key: '1',
children: [...result.value],
}],
defaultExpandedKeys:result.value[0].key,
isLoading:false
})
}
addIsLeaf = (treenode) =>{
treenode.forEach((item)=>{
if(item.children.length === 0 ){
item.isLeaf =true
}else{
this.addIsLeaf(item.children)
}
})
}
componentDidMount(){
this.getTreeNode();
}
onSelect =async (keys,info) =>{
this.setState({NodeTreeItem:null});
const {key,pos} = info.node;
//这里写点击tree节点的事件逻辑
}
//右键点击事件(注意,这里的右键的Tooltip位置不是很精确,需要微调)
onRightClick = ({event,node}) => {
var x = -75;
var y = event.clientY - 112 ;
const pos = node.pos.split('-').length - 1;
if(pos === 1){
this.setState({
NodeTreeItem: {
pageX: x,
pageY: y,
key: node.key,
name: node.title,
pos:pos
},
isHideUpdate:'none',
isHideDelete:'none'
});
}else if(pos === 3){
this.setState({
NodeTreeItem: {
pageX: x,
pageY: y,
key: node.key,
name: node.title,
pos:pos
},
isHideAdd:'none'
});
}else{
this.setState({
NodeTreeItem: {
pageX: x,
pageY: y,
key: node.key,
name: node.title,
pos:pos
},
isHideAdd:'',
isHideUpdate:'',
isHideDelete:''
});
}
}
//增删改组件
getNodeTreeMenu() {
const {pageX, pageY} = {...this.state.NodeTreeItem};
const tmpStyle = {
position: 'absolute',
maxHeight: 40,
textAlign: 'center',
left: `${pageX}px`,
top: `${pageY}px`,
display: 'flex',
flexDirection: 'row',
};
const menu = (
<div
style={tmpStyle}
>
<div style={{alignSelf: 'center', marginLeft: 10,display:this.state.isHideAdd}} onClick={this.handleAddSub}>
<Tooltip placement="bottom" title="添加子节点" >
<PlusCircleOutlined />
</Tooltip>
</div>
<div style={{alignSelf: 'center', marginLeft: 10,display:this.state.isHideUpdate}} onClick={this.handleEditSub}>
<Tooltip placement="bottom" title="修改节点">
<EditOutlined />
</Tooltip>
</div>
{this.state.NodeTreeItem.category === 1?'':(
<div style={{alignSelf: 'center', marginLeft: 10,display:this.state.isHideDelete}} onClick={this.handleDeleteSub}>
<Tooltip placement="bottom" title="删除该节点">
<MinusCircleOutlined />
</Tooltip>
</div>
)}
</div>
);
return (this.state.NodeTreeItem == null) ? '' : this.state.role ===
0 ? menu : '';
}
//添加按钮弹出添加Modal
handleAddSub = () =>{
this.setState({isModalVisible:true,operType:'add'})
}
//修改按钮弹出修改Modal
handleEditSub = () => {
const {NodeTreeItem} = this.state;
this.setState({isModalVisible:true,operType:'update'})
this.formRef.current.setFieldsValue({name:NodeTreeItem.name});
}
//删除按钮弹出删除Modal
handleDeleteSub = () => {
this.setState({isModalVisible:true,operType:'delete'})
}
//节点添加方法
toAdd = async (values) => {
const {NodeTreeItem} = this.state;
const result = await reqAddTreeNode(values.name,NodeTreeItem.key);
if(result.msg === 'success'){
message.success('节点添加成功')
}else{
message.error('节点添加失败,请重试')
}
this.setState({isModalVisible:false})
this.getTreeNode();
}
//节点更新方法
toUpdate = async (values) => {
const {NodeTreeItem} = this.state;
const result = await reqUpdateTreeNode(NodeTreeItem.key,values.name,NodeTreeItem.pos);
if(result.msg === 'success'){
message.success('节点修改成功')
}else{
message.error('节点修改失败,请重试')
}
this.setState({isModalVisible:false})
this.getTreeNode();
}
//节点删除方法
toDelete = async () => {
const {NodeTreeItem} = this.state;
const result = await reqDeleteTreeNode(NodeTreeItem.key,NodeTreeItem.pos);
if(result.msg === 'success'){
message.success('节点删除成功')
}else{
message.error('节点删除失败,请重试')
}
this.setState({isModalVisible:false,NodeTreeItem:null})
this.getTreeNode();
}
//Modal确定的回调
handleOk = () => {
const {operType} = this.state;
this.formRef.current.validateFields().then(values=>{
if(operType==='add'){
this.toAdd(values);
}else if(operType==='update'){
this.toUpdate(values);
}else{
this.toDelete();
}
}).catch(reason=>{
message.warning('表单输入不允许为空,请检查');
})
}
//Modal取消的回调
handleCancel=(e)=>{
this.formRef.current.resetFields();
this.setState(()=>{
return({isModalVisible:false})
});
}
render() {
const {isModalVisible,operType,treeData,isLoading,defaultExpandedKeys} = this.state;
if(isLoading == true){
return null
}else{
return (
<>
<div style={{display: 'flex',marginRight:'20px'}}>
<DirectoryTree
multiple
defaultExpandAll
// defaultExpandedKeys={}
onSelect={this.onSelect}
treeData={treeData}
onRightClick={this.onRightClick}
style={{width:'250px'}}
/>
<div style={{position:'relative',}}>
{this.state.NodeTreeItem != null ? this.getNodeTreeMenu() : ""}
</div>
</div>
<Modal
title={operType === 'add' ? '添加节点' : operType === 'delete' ? '删除节点' : '修改节点'}
visible={isModalVisible}
onOk={this.handleOk}
okText="确定"
onCancel={this.handleCancel}
cancelText="取消"
forceRender={true}
>
{operType === 'add' ? '请输入要添加节点的名称' : operType === 'delete' ? '您确定要删除该节点吗?' : '请输入要修改节点的名称'}
<Form
name="normal"
ref={this.formRef}
style={{display:operType === 'delete' ? 'none' : ''}}
>
<Form.Item
name="name"
rules={[
{required: operType === 'delete'? false : true,message: '节点名称不允许为空'},
]}
>
<Input placeholder="请输入节点名称" />
</Form.Item>
</Form>
</Modal>
</>
)
}
}
}
乾坤未定,你我皆是黑马!