实现Ant Design Tree组件的节点的增删改

在做项目时最近遇到一个需求,需要用到Antd中的tree,并能够实现对tree的节点的增加和删除,以及节点名称的修改。去翻Antd官网文档,发现tree组件并没有提供关于节点操作的api,但是有鼠标右击的api。借助这个鼠标右击,以及其他组件是可以实现对节点的增删改。下面进行截图介绍:

截图介绍

第一部分:Tree组件

  1. 最外层节点只能增加子节点
  2. 父节点可以增加子节点,修改自己的节点名称,删除节点

3.最内层节点不允许再添加子节点,只允许修改自己的节点名称和删除该节点

ant design 树形数据table展示 antd树形控件增删_javascript

第二部分:Tooltip组件

4.点击添加子节点。这里用到了Tooltip组件,包装成button,设置点击事件弹出Model框输入节点名称以添加

ant design 树形数据table展示 antd树形控件增删_react.js_02


5.修改节点

ant design 树形数据table展示 antd树形控件增删_javascript_03


6.删除节点

ant design 树形数据table展示 antd树形控件增删_前端框架_04

第三部分: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>
            </>
        )
      }
        
    }
}

乾坤未定,你我皆是黑马!